The embedded controller (EC) is a small, always powered microcontroller on a laptop's mainboard that handles the jobs the main processor should not have to: scanning the keyboard matrix, charging the battery, spinning the fans, watching temperatures, reading the lid switch and power button, driving status LEDs and sequencing the power rails that bring the main processor up. Its firmware is updated through the same channels as the rest of the platform firmware, usually a UEFI capsule delivered by the OS or by fwupd, and on Chromebooks it is verified and refreshed at every boot by a process called EC software sync.
That short answer hides a lot. The EC is usually the first chip on the board to run code, and NIST's platform firmware guidance notes that it often holds the main processor in reset until it is ready. It talks to the operating system through an interface the ACPI specification defines, and to the battery pack over SMBus using commands from a specification first published in the 1990s. Some laptops run fully open source EC firmware; most run closed code you can only update, not inspect. This post explains what the EC does, how it is wired in, where its firmware lives, how updates are signed and checked, what public research has shown about its risks, and how to read and update EC versions on Linux safely.
Key takeaways
- The EC is a separate microcontroller (System76's laptops, for example, use 8051 compatible parts) that runs whenever the battery or charger supplies power, even when the laptop looks off.
- It owns the keyboard matrix, battery charging, fan and thermal control, power sequencing, the lid switch, the power button and LEDs. NIST SP 800-193 describes it as typically "the first system board device in the platform to execute code".
- The operating system talks to it through the ACPI embedded controller interface: two I/O ports, five commands (read, write, burst enable, burst disable and query) and query events that fire ACPI
_Qxxmethods. - The EC usually reaches the battery over SMBus using the Smart Battery Data Specification, Revision 1.1 of which is dated 11 December 1998.
- Open source EC firmware exists. The ChromeOS EC is open source and, since roughly July 2021, new Chromebook designs use a Zephyr RTOS based build. Framework maintains a downstream fork of it, and System76 publishes GPLv3 EC firmware for its laptops. Most other laptops ship closed EC code.
- EC firmware lives either in the controller's own flash or in a region of a shared SPI flash chip. On most PCs it is updated as part of a UEFI capsule; on Chromebooks the main firmware carries a copy of the EC's read/write image and re-flashes the EC at boot if the hash does not match.
- Public research going back to 2010 and 2011 showed that modified EC and battery firmware can hide code outside the operating system's view and, for batteries, potentially create safety hazards. NIST SP 800-193 (May 2018) asks for protection, detection and recovery for exactly this kind of firmware.
- Always update EC firmware on AC power with a charged battery, never interrupt it, and expect the laptop to power off completely as the EC resets.
What is the embedded controller, and what does it handle?
An embedded controller is a microcontroller with its own CPU core, RAM, flash or ROM, timers, analog inputs and a large number of general purpose pins. It sits on the mainboard next to the main system on a chip (the chip that runs your operating system, which ChromeOS documentation calls the application processor or AP) and stays powered from the always on rail whenever there is a battery or a charger connected.
The ChromeOS EC README describes its open source EC firmware as "a lightweight, multitasking OS with modules for power sequencing, keyboard control, thermal control, battery charging, and verified boot." The System76 EC controllers page gives a more hardware oriented list of what its EC uses each block for:
| EC block | What it does in a laptop |
|---|---|
| ADC (analog to digital converter) | Reads battery voltages and thermistor temperatures |
| DAC (digital to analog converter) | Controls keyboard backlight brightness |
| GPIO | Drives LEDs, reads buttons and switches enable lines for other hardware |
| Keyboard scan controller | Detects key presses on the internal keyboard matrix |
| LPC (or eSPI) | Exposes EC functions to the host processor |
| PECI | Reads CPU temperature relative to its throttle point |
| PS/2 | Talks to the touchpad on designs that use PS/2 |
| PWM | Sets fan speed and LED brightness |
| SMBus | Reads battery information |
| SPI | Reads and programs the EC's own firmware |
| UART | Provides an EC debug console |
Put together, the EC's daily work looks like this:
- Keyboard matrix. Laptop keyboards are a grid of rows and columns. The EC drives the columns, reads the rows and turns presses into scan codes the host understands. On many x86 laptops the EC also emulates the legacy 8042 keyboard controller that PC software has expected since the 1980s, which is why older documents call it the "KBC".
- Battery charging. The EC reads the battery pack's state over SMBus, programs the charger chip with the voltage and current the pack asks for, and decides when to start, taper and stop charging.
- Fans and thermals. It reads thermistors and the CPU's temperature and adjusts fan PWM duty. The ChromeOS EC console even has commands to override this for testing (
fandutyandautofan). - Power sequencing. Bringing up a modern laptop board means switching on many voltage rails in a fixed order and checking that each is good before the next. The EC does this, then releases the main processor from reset. It also handles sleep, hibernate and shutdown transitions.
- Lid switch and power button. The lid's magnetic sensor and the power button are wired to the EC, which decides whether to wake the system and tells the OS through an event.
- LEDs and small peripherals. Charge LEDs, caps lock lights, keyboard backlights and sometimes ambient light sensors or accelerometers.
- USB Type-C power. On newer designs the EC also manages USB Power Delivery negotiation. The Zephyr EC documentation lists USB Power Delivery alongside battery charging, power sequencing, keyboard handling and verified boot support as shared EC features.
NIST draws the same picture from the policy side. In SP 800-193, the embedded controller and its desktop cousin, the Super I/O chip, are the first entry in the list of platform devices. The guideline says an EC "is typically associated with mobile platforms" and typically controls "the keyboard, LEDs, fans, battery monitoring/charging, thermal monitoring, etc." It then adds the detail that matters most for security: the EC is "typically the first system board device in the platform to execute code, even holding the host processor in reset until the EC/SIO is ready".
Why a separate chip?
Three reasons recur in vendor and project documentation. First, the EC must run when the main processor is off: it is the thing that notices you pressed the power button. Second, charging and thermal protection need to keep working if the OS hangs or crashes. Third, low power. A small microcontroller can scan a keyboard and watch a battery while drawing a tiny fraction of the power the main SoC would need.
The ChromeOS EC README describes the constraints this creates in its own code: each task "has a fixed stack size and there is no heap (malloc)", all storage must be declared at build time, and a watchdog reboots the EC if a task runs for too long. That is a very different environment from UEFI firmware or an operating system, and it shapes how EC bugs look and how updates have to be done.
Where does the EC sit on the board?
The ChromeOS EC glossary explains how the EC connects to the host. On x86 systems it uses either LPC or eSPI:
- LPC (Low Pin Count bus) is the legacy link. The glossary says it runs at 33 MHz with about 133 Mbps of bandwidth and has been replaced by eSPI.
- eSPI (Enhanced Serial Peripheral Interface) is Intel's newer interface between the processor's platform controller and the EC, with quad I/O and clock speeds up to 66 MHz, giving up to 264 Mbps according to the same glossary.
- Arm based Chromebooks connect the EC over SPI (or I2C on some designs), with the main processor as the SPI controller and the EC as the peripheral.
Through LPC or eSPI, the EC exposes I/O ports and sometimes a shared memory window to the host. Those ports are where the ACPI interface lives.
How does the operating system talk to the EC?
There are two layers. On most x86 laptops the OS uses the standard ACPI embedded controller interface, so a generic driver works across many vendors. Some platforms add a richer vendor protocol on top; ChromeOS devices use "host commands" with their own kernel driver and user space tool.
The ACPI embedded controller interface
The ACPI specification devotes a chapter to the embedded controller interface (chapter 12 in ACPI 6.5). The spec site blocks scripted downloads, so the details below come from the Linux kernel's ACPI EC driver, which implements that chapter and quotes its constants directly.
The interface is two I/O ports and a small command set:
- EC_SC, the status and command port. Reading it returns status flags; writing it sends a command.
- EC_DATA, the data port, used to pass addresses and values.
The status register flags defined in the kernel driver are:
| Flag | Value | Meaning |
|---|---|---|
| OBF | 0x01 | Output buffer full: the EC has a byte for the host to read |
| IBF | 0x02 | Input buffer full: the EC has not consumed the last byte the host wrote |
| CMD | 0x08 | The input buffer holds a command rather than data |
| BURST | 0x10 | The EC is in burst mode |
| SCI_EVT | 0x20 | The EC has an event pending for the host |
And the commands:
| Command | Value | Purpose |
|---|---|---|
| Read (RD_EC) | 0x80 | Read one byte from the EC's address space |
| Write (WR_EC) | 0x81 | Write one byte to the EC's address space |
| Burst enable (BE_EC) | 0x82 | Ask the EC to give the host exclusive, fast access for a sequence of transfers |
| Burst disable (BD_EC) | 0x83 | Return the EC to normal mode |
| Query (QR_EC) | 0x84 | Ask the EC which event it raised |
Every transfer is a handshake: the host waits for IBF to clear before writing, and waits for OBF to set before reading. It is slow and byte by byte, which is why the spec added burst mode, and why the Linux driver has tunables such as ec_delay, ec_busy_polling and ec_polling_guard.
The EC exposes a 256 byte address space through those read and write commands. Platform firmware describes what each byte means inside the ACPI tables (the DSDT) using an OperationRegion of type EmbeddedControl. The Linux driver registers a handler for that address space (ACPI_ADR_SPACE_EC), so when ACPI code reads a field called, say, battery remaining capacity, the kernel turns that into EC read commands. That is the key idea: the OS does not need to know a vendor's EC register map, because the firmware's ACPI code carries it.
The EC device appears in the ACPI namespace with the hardware ID PNP0C09. Platforms can also provide an ECDT table, which lets the OS reach the EC early in boot, before the full namespace is loaded. The Linux driver handles both, and its comments record real world quirks where firmware tables disagree with each other, for example a platform where it must trust the ECDT GPE number rather than the one from the _GPE method.
EC query events and _Qxx methods
Most interesting EC activity starts on the EC side: the lid closed, the charger was unplugged, a hotkey was pressed, a temperature crossed a threshold. The EC signals this by setting SCI_EVT and raising a system control interrupt through a general purpose event (GPE). The OS then sends the query command (0x84), and the EC returns a one byte event number. The OS runs the ACPI method named _Qxx, where xx is that number in hex. The Linux driver literally scans for methods matching _Q%x.
So _Q0A might notify the OS that the AC adapter state changed, and the ACPI code inside that method calls Notify on the AC adapter device. The method names are defined per platform in the DSDT, which is why a stuck or noisy EC event shows up as a GPE storm on one model and not another. The Linux driver tracks this with an ec_storm_threshold parameter and can switch to polling when a GPE fires too often.
SMBus and the Smart Battery System
The battery pack has its own microcontroller, usually called a gas gauge or fuel gauge, which measures current, voltage and temperature and estimates state of charge. The EC reaches it over SMBus, a two wire bus derived from I2C. The language they speak is defined by the Smart Battery System (SBS) specifications, maintained by the SBS Implementers Forum.
The current set lists the Smart Battery Charger Specification 1.1, the Smart Battery Data Specification 1.1 (with an errata and a 2007 fuel cell addendum), the Smart Battery Selector Specification 1.1, the Smart Battery System Manager Specification 1.0 and data accuracy testing guidelines. The Smart Battery Data Specification, Revision 1.1 is dated 11 December 1998 and defines commands such as:
| SBS command | Code | What it returns or sets |
|---|---|---|
| ManufacturerAccess() | 0x00 | Vendor specific access, used for things like sealing and unsealing |
| Temperature() | 0x08 | Pack temperature |
| Voltage() | 0x09 | Pack voltage |
| Current() | 0x0a | Present current |
| RelativeStateOfCharge() | 0x0d | Percent of full charge capacity |
| FullChargeCapacity() | 0x10 | Capacity when fully charged now |
| ChargingCurrent() | 0x14 | The current the battery asks the charger for |
| ChargingVoltage() | 0x15 | The voltage the battery asks the charger for |
| BatteryStatus() | 0x16 | Alarm and status bits |
| CycleCount() | 0x17 | Charge cycles so far |
| DesignCapacity() | 0x18 | Capacity when new |
| SerialNumber() | 0x1c | Pack serial number |
The design point to notice is that the battery tells the charger what it wants. The spec describes the battery broadcasting ChargingVoltage(), ChargingCurrent() and alarm warnings to the charger, and the charger using those values to control charging. That is why battery pack firmware is part of the safety chain, which we come back to below.
The OS normally sees battery data indirectly. ACPI methods such as _BIX (battery information) and _BST (battery status) run inside the firmware's ACPI code, read EC registers through the EC address space, and the EC in turn has already polled the pack over SMBus. Linux turns the result into /sys/class/power_supply/BAT0.
ChromeOS host commands
ChromeOS devices go further. Their AP to EC communication document describes host commands, each identified by a command ID and a version number. The host writes a request packet (a transport header, a struct ec_host_request with command ID, length and checksum, and parameters) and reads back a response with a result code and checksum. The transport can be LPC or eSPI on x86, or SPI or I2C on Arm.
In practice the user space tool ectool sends raw commands through the cros-ec kernel driver, and other kernel drivers use host commands to plug EC features into normal Linux subsystems; the document gives the example of EC sensors exposed through the Industrial I/O subsystem. On the EC side, the packet is validated and passed to a handler that runs in the HOSTCMD task.
Where does open source EC firmware exist, and what stays proprietary?
As of October 2026, three families of laptop EC firmware are developed in public.
ChromeOS EC (legacy and Zephyr based)
The ChromeOS EC repository is open source and written in C. Its README says it supports "a variety of micro-controllers" and that compatible devices include all Chromebooks shipped after the Chromebook Pixel (2013). It also notes the term "EC" has spread: the same OS now runs on other microcontrollers in Chromebooks, such as the fingerprint MCU (FPMCU) and a touchpad controller.
The README now opens with a note that it covers the legacy implementation, used by Chromebook reference designs prior to July 2021. The Zephyr EC introduction says that "starting roughly in July of 2021", Chromebooks switched to an EC application based on the Zephyr Project RTOS. The two implementations share a large body of code: battery charging, USB Power Delivery, AP chipset power sequencing, sensor support, keyboard handling and verified boot support all live in the shared common/ directory, while low level chip support comes from Zephyr. Google keeps a local mirror of upstream Zephyr and merges upstream changes daily, according to the same page. Zephyr EC binaries are built with a meta build tool called zmake.
Framework
The Framework EmbeddedController repository describes itself as "a downstream fork of the Chrome EC firmware used by Chromebooks". Its README lists one branch per system and CPU generation, with an EC codename and whether that branch is Zephyr based. At the time of writing, the 11th, 12th and 13th Gen Intel Core Laptop 13 boards use a non Zephyr branch, while the AMD Ryzen 7000, Ryzen AI 300, Intel Core Ultra Series 1 and Series 3 Laptop 13 boards, the Laptop 16 boards, the Laptop 12 and the Desktop are listed as Zephyr based.
Framework also publishes a system tool, framework-system, which runs on Linux, Windows and the UEFI shell and can report firmware versions, battery and AC state, and parse EC binaries (legacy and Zephyr based).
System76
The System76 EC repository is "a GPLv3 licensed embedded controller firmware for System76 laptops". It targets 8 bit 8051 compatible ITE controllers (IT8587E and IT5570E) and is built with make BOARD=system76/<model>. Its tools are separately licensed: the firmware is GPL-3.0-only, ecflash is LGPL-2.1-or-later and its ectool and simulator are MIT. The EC has no separate tagged releases; in official releases it shares the BIOS version, and the README shows how to find the EC commit for a given open firmware release with git ls-tree.
What remains proprietary
Most laptops still ship EC firmware that is closed and only available as a binary inside a vendor's firmware update. Even the open projects depend on closed information: the System76 README notes that datasheets for the ITE controllers it uses "cannot be shared outside of company", though a related part's datasheet is public. Other closed pieces sit next to the EC: USB Power Delivery controller firmware (Framework's tool reports PD controller versions separately), battery gas gauge firmware, touchpad and fingerprint sensor firmware, and of course the CPU vendor's security processor, which we cover in the comparison below.
The practical consequence for a security team is that "EC version" is usually just a string in a vendor's release notes. You can track it, but you cannot rebuild it, diff it or scan it.
Where does EC firmware live, and how is it updated?
Storage: own flash or shared SPI flash
There are two common layouts.
- The EC has its own flash. Many EC microcontrollers include internal flash, or have a small dedicated SPI flash chip. System76 lists SPI on its EC as the interface that "reads and programs the EC's firmware". ChromeOS ECs keep a read only (RO) image and a read/write (RW) image in their flash.
- The EC shares the main SPI flash. On some x86 designs the EC loads its code from a region of the same SPI flash chip that holds the UEFI image. In that case an update to "the BIOS" may rewrite the EC region at the same time, and protecting the flash chip protects both.
Which layout your laptop uses is a design decision you usually cannot see from the OS. Vendor release notes sometimes say "this BIOS update also updates the EC to version X", which is a hint that the two are packaged together, whatever the physical layout.
Update channels
| Channel | How it works | Typical platforms |
|---|---|---|
| UEFI capsule | The OS stages a signed capsule; on reboot the platform firmware validates it and writes the system firmware and EC regions | Most Windows and Linux laptops, often via fwupd and the LVFS on Linux |
| Vendor firmware updater | A UEFI or OS application from the vendor writes both firmware and EC | System76 firmware-update, many vendor Windows tools |
| ChromeOS software sync | The AP firmware carries the EC RW image and refreshes the EC at boot | Chromebooks and ChromeOS derived designs |
| Internal programmer | Writing the EC flash from the running OS through an unlocked EC | Developers on open EC platforms |
| External programmer | A hardware programmer attached to the board with power removed | Recovery of a bricked EC, first install of open firmware |
UEFI capsules and fwupd. The fwupd project is the Linux daemon that discovers updatable devices and applies firmware from the Linux Vendor Firmware Service (LVFS). Its UEFI capsule plugin explains that the UEFI UpdateCapsule service is used to update system firmware: fwupd extracts a capsule from a cabinet archive, stages it, and a companion EFI application (fwupd-efi) or a supporting bootloader hands it to the firmware on the next boot. With Secure Boot enabled, that companion binary has to be signed by an authority trusted by shim or the platform. The firmware then validates the capsule's signature before writing anything. If your vendor bundles the EC with the system firmware capsule, this is how your EC gets updated on Linux. We cover capsules in more depth in firmware updates on Linux with fwupd and LVFS.
fwupd also has a ChromeOS EC plugin that updates ChromeOS EC based devices over a USB endpoint, based on the EC project's usb_updater2. It handles detachable keyboards and similar accessories that run the ChromeOS EC, not the main EC inside a Chromebook, which is updated by software sync.
Vendor updaters. System76's flashing guide says the firmware-update UEFI application used for normal system updates flashes both the system BIOS and the EC. Its internal programmer method only works if the EC firmware is not write locked (built with CONFIG_SECURITY=y), and warns that flashing triggers a watchdog reset that makes the system "immediately power off", so unsaved work can be lost.
External programmers. When EC firmware is corrupted, the only way back is often a hardware programmer. System76's guide describes an external method using a microcontroller board connected to the keyboard port, with the battery and AC disconnected first. The ChromeOS EC README describes flashing through a Servo debug board, and notes the EC "must be powered either by external power or a charged battery for re-flashing to succeed".
How is EC firmware signed and verified?
Signing practice varies widely, and on closed platforms it is rarely documented. The best public description is ChromeOS, so it is worth walking through.
RO and RW images. The ChromeOS write protection document explains that the EC has RO and RW firmware. Out of reset the EC boots its RO image, which is locked at the factory and never changed. The RO firmware boots the host and asks it to verify a hash of the RW firmware. If the RW image is invalid, it is updated from a copy in the host's RW firmware. Once validated, the EC jumps to RW without rebooting.
Software sync. The README explains the rest. The RW EC image is stored inside the RW part of the main system firmware. At boot, if the EC's RW firmware does not match the copy in system firmware, the EC's RW section is re-flashed. This makes updating the EC and the system firmware "a unified operation": ChromeOS updates the main firmware, and the EC follows on the next boot. The main firmware itself is verified by vboot, so the EC RW image inherits that chain of trust. Developers can disable software sync with a Google Binary Block flag, but only with write protection off.
Write protection. The same document says that on modern ChromeOS devices the security chip (Cr50, also called the GSC) drives a hardware write protect signal connected to the AP SPI flash, the EC SPI flash, an EEPROM and the fingerprint MCU. Disabling it requires a debug cable flow ("CCD open") or Servo. Older devices used a physical write protect screw, and removing the battery also disables hardware write protect, a method used mainly during bring up. Software write protect is stored in non volatile memory: if hardware write protect is on, software write protect can be enabled but not disabled. The EC's RW region is left unprotected at EC boot until the host verifies it, and is protected before the Linux kernel loads.
Fingerprint MCU contrast. For the fingerprint MCU, the document says the RO image uses an embedded public key to validate the RW image's signature directly. That is the more common pattern on other platforms too: an immutable boot stage that checks a signature before running updatable code.
On closed platforms, the most you can usually confirm is that the EC update is inside a signed capsule. Whether the EC itself checks a signature on its own code at every boot, keeps a recovery copy, or can be rolled back to an older version is a question for the vendor. NIST SP 800-193 gives you a vocabulary for asking it.
What has public research shown about EC firmware risks?
Research on EC and battery firmware is older than many people expect. The examples below are described at the level of mechanism and lesson only.
| Date | Work | What it showed (conceptually) | Source |
|---|---|---|---|
| 11 Dec 1998 | Smart Battery Data Specification 1.1 | Defines how battery, charger and host exchange charge requests and alarms over SMBus | SBS-IF |
| 2010 | Ralf-Philipp Weinmann, "The hidden nemesis: Backdooring embedded controllers", ToorCon | Proposed a keylogger inside an EC (as cited by Gazet, 2011) | Gazet 2011 references |
| June 2011 | Alexandre Gazet, "Sticky fingers & KBC Custom Shop", SSTIC 2011 | Studied a laptop's BIOS password recovery path, then modified the keyboard controller code so changes persisted while the laptop had power, giving code that ran out of view of the main CPU and OS | SSTIC 2011 paper |
| 12 Jul 2011 | Charlie Miller, "Battery Firmware Hacking" (Black Hat USA 2011) | Reverse engineered a smart battery gas gauge and its update process; default unseal and full access passwords plus a checksum (not a signature) allowed reprogramming | Miller white paper |
| May 2018 | NIST SP 800-193, Platform Firmware Resiliency Guidelines | Names the EC as a platform device whose firmware needs protection, detection and recovery | NIST |
| Jul 2021 | ChromeOS EC moves to a Zephyr based build for new designs | Open source EC firmware moves onto a maintained RTOS with daily upstream merges | ChromeOS EC docs |
Hidden code outside the OS
Gazet's SSTIC paper began with a mundane question, how a laptop's BIOS master password recovery worked, and ended in the keyboard controller. After studying vendor update packages he was able to modify the controller's code. He describes adding a command that let him read the controller's full memory, a hook that logged the commands exchanged with the system management mode handler even across reboots, and a command to write bytes to controller RAM. His conclusion is the general lesson: an attacker who controls the EC can hide and run code on an autonomous processor, "à l'insu du processeur principal" (without the main processor's knowledge), and therefore without the OS knowing. He was also careful to say the specific attack was limited by tight hardware and software constraints, but that the concepts are generic.
Battery packs as a firmware target
Miller's white paper, dated 12 July 2011, looked at the gas gauge controller inside a widely sold laptop line's batteries. He explains that packs ship sealed, and that unsealing and a higher "full access" mode each need a password, after which the firmware can be read or written subject to a checksum meant to catch accidental changes. In the packs he tested, both passwords were the chip maker's documented defaults. His concluding warning is the one to remember: "changes made to the smart battery firmware may cause safety hazards such as overcharging, overheating, or even fire." He also raised persistence (a modified battery survives an OS reinstall) and the idea of observing other traffic on the same bus.
The lesson for platform builders is not specific to one product: a checksum detects accidents, not attackers; default credentials on a programmable component are a firmware integrity problem; and anything on the SMBus can affect what the charger is told to do.
What NIST SP 800-193 asks for
NIST SP 800-193, published May 2018, organizes platform firmware resiliency around three principles:
- Protection: mechanisms that keep platform firmware code and critical data in a state of integrity and protect them from corruption, such as authenticated updates and write protection.
- Detection: mechanisms that detect when firmware code and critical data have been corrupted or changed from an authorized state.
- Recovery: mechanisms that restore firmware code and critical data to a state of integrity when corruption is detected or when recovery is forced through an authorized mechanism.
The document builds these on roots of trust for update, detection and recovery, and it explicitly lists the EC/SIO as a platform device in scope, alongside the TPM, network controllers, storage and the BMC. It also mentions service processors such as the EC or BMC as a possible trusted path for physical presence checks. Read through an EC lens, the ChromeOS design maps cleanly: write protected RO is protection, the host's hash check of RW at boot is detection, and re-flashing RW from the verified system firmware copy is recovery. For other laptops, those three words make a good procurement question.
How does battery pack firmware fit in, and why does it matter for safety?
A laptop battery is not just cells. A pack contains lithium ion cells, a protection circuit that can disconnect the cells, a gas gauge microcontroller with firmware and calibration data, and a thermistor or two. The gas gauge is effectively a second embedded controller with its own update path.
Safety is layered:
- The cells have their own physical limits and, in many designs, thermal fuses or similar passive protection.
- The pack's protection circuitry and gas gauge decide whether charging is allowed, track cycle count and temperature, and request a charging voltage and current using the SBS
ChargingVoltage()andChargingCurrent()values. - The charger and the EC apply those requests, enforce their own limits and report status to the OS.
- The OS reads the result for display and power policy, and can usually set charge thresholds through the EC.
Because the battery asks and the charger obeys, wrong values in battery firmware or calibration data can push the system toward unsafe charging, which is exactly the hazard Miller warned about. That is also why EC firmware updates sometimes change charging behaviour: the EC decides how to taper, when to stop at a charge limit and how to react to a battery alarm. The ChromeOS EC's low battery startup guide shows how subtle this gets: near empty, several features interact and the EC has to decide whether there is enough power to start the system without browning out.
For users and admins the takeaways are simple: use the vendor's battery, apply EC and firmware updates that mention charging or battery fixes, and treat swelling or unusual heat as a hardware problem, not something firmware can fix.
Comparison: EC, BMC, Intel CSME or AMD PSP, and UEFI firmware
The EC is one of several pieces of firmware running beneath your OS. This table compares them by job, location, signer and update path.
| Embedded controller (EC) | Baseboard management controller (BMC) | Intel CSME or AMD PSP | UEFI system firmware | |
|---|---|---|---|---|
| Main job | Keyboard, battery charging, fans and thermals, power sequencing, lid, buttons, LEDs | Remote server management: power, console, sensors, firmware updates out of band | Platform security engine: early boot security, firmware TPM on some platforms, other security services | Initialize the platform, run Secure Boot, load the OS loader, provide ACPI tables and runtime services |
| Typical device | Laptops, tablets, some mini PCs (Super I/O on desktops) | Servers, some workstations | Nearly every recent Intel or AMD PC | Every modern PC and server |
| Where it runs | Separate microcontroller on the mainboard | Separate SoC with its own network port or shared NIC | A dedicated core inside the chipset or CPU package | The main CPU, before and alongside the OS |
| Runs when the PC looks off | Yes, whenever battery or charger power is present | Yes, on standby power | Yes, in some power states | No |
| Who signs it | Varies: the laptop maker, often inside the system firmware capsule; ChromeOS EC RW is covered by vboot | The server or BMC firmware vendor | The CPU vendor | The PC maker (built from an independent BIOS vendor's or open source code) |
| How it is updated | UEFI capsule, vendor updater, ChromeOS software sync, external programmer | BMC web UI, Redfish, IPMI tools, vendor packages | Bundled in system firmware updates from the PC maker | UEFI capsule (fwupd on Linux), vendor tools |
| Open source options | ChromeOS EC (including Zephyr builds), Framework fork, System76 EC | OpenBMC | None for the firmware itself | coreboot with payloads, EDK II based builds |
| How you check the version | fwupd, vendor tools, ectool on ChromeOS, release notes | BMC UI or Redfish | Vendor tools, fwupd on supported systems | dmidecode, fwupd, firmware setup screen |
For deeper dives on the neighbours, see Intel CSME and AMD PSP explained, coreboot explained, OpenBMC explained and CPU microcode updates explained. The motherboard evolution post shows how these pieces arrived over time, and how a laptop is made puts the EC in the context of the whole build.
Step by step: read EC and firmware versions on Linux and update safely
These steps work on most Linux laptops. Not every command applies to every device: ectool only works on ChromeOS EC based hardware, and fwupd only shows the EC separately if the vendor exposes it that way.
Step 1: See what the kernel found
# Kernel messages from the ACPI EC driver: ports, GPE number, ECDT or DSDT
sudo dmesg | grep -i "ACPI: EC"
# Example output shape (values differ per machine):
# ACPI: EC: EC started
# ACPI: EC: interrupt blocked
# ACPI: EC: EC_CMD/EC_SC=0x66, EC_DATA=0x62
# ACPI: EC: Boot ECDT EC used to handle transactions
The EC_CMD/EC_SC and EC_DATA lines are the two ACPI EC ports described earlier, printed by the kernel driver. If you see a GPE number, you can watch how often the EC raises events. The kernel's ACPI sysfs ABI documentation describes these per GPE counters under /sys/firmware/acpi/interrupts/:
# Replace 6E with the GPE number from dmesg, in hex, upper case
cat /sys/firmware/acpi/interrupts/gpe6E
# A count that climbs by thousands per second points to an event storm
watch -n1 cat /sys/firmware/acpi/interrupts/gpe6E
Step 2: Read battery data that the EC collected
# Battery data from ACPI, which reads it from the EC, which polled the pack over SMBus
cat /sys/class/power_supply/BAT0/uevent
# A friendlier view, if upower is installed
upower -i "$(upower -e | grep -i bat)"
Look at cycle count, design capacity versus full charge capacity, and the reported status. These come from the SBS values in the tables above.
Step 3: List firmware versions with fwupd
# Install fwupd if needed (Debian and Ubuntu shown; use dnf or pacman elsewhere)
sudo apt install fwupd
# Show every device fwupd knows about, with current versions and update support
fwupdmgr get-devices
# Refresh metadata from the LVFS and list available updates
fwupdmgr refresh
fwupdmgr get-updates
On many laptops you will see "System Firmware" with a version and a GUID taken from the UEFI ESRT table. Some vendors expose the EC as its own device; others fold it into system firmware. Check the release notes for the update to see whether it includes an EC change.
Step 4: Read the EC version with vendor or project tools
On ChromeOS EC based hardware (Chromebooks with developer mode, and devices built on the same EC), the ectool source defines version ("Prints EC version"), battery ("Prints battery info"), chargestate and flashprotect commands:
# Ask the EC for its RO and RW versions and which copy is running
sudo ectool version
# Battery and charging state as the EC sees it
sudo ectool battery
On Framework laptops, the project's tool reports UEFI, EC and PD controller versions:
sudo framework_tool --versions
The project's examples show output with an "EC Firmware" section containing the build version and the current image (RO or RW).
On System76 laptops with open EC firmware, the EC shares the BIOS version, so the system firmware version tells you which EC commit you run.
On other laptops, use the vendor's own tool or the firmware setup screen, and compare against the vendor's release notes.
Step 5: Prepare for the update
Before you apply any update that touches the EC:
- Connect AC power and charge the battery above 50 percent. EC flashing can briefly cut power paths, and the EC itself resets.
- Save work and close applications. Expect a full power off rather than a normal reboot when the EC restarts. System76's guide warns its internal flash method causes the system to power off immediately.
- Check the device and version. Confirm that the update fwupd offers matches your model and that the target version is the one in the vendor's notes.
- Do not interrupt. Do not close the lid, unplug the charger or hold the power button during the update, even if the screen goes dark for a while.
- Keep a recovery plan. Know whether your model has a recovery mode or a vendor recovery procedure for failed firmware updates.
Step 6: Apply the update
# Check the device list one more time and note the device ID or name
fwupdmgr get-devices
# Apply all available updates; fwupd will ask before rebooting
fwupdmgr update
# After the reboot, confirm the result
fwupdmgr get-history
fwupdmgr get-devices
For UEFI capsules, fwupd stages the update and the actual write happens during the next boot, often with a vendor progress screen. Leave the machine alone until it boots back into the OS.
Step 7: Verify after the update
# Version should have changed
fwupdmgr get-devices
sudo framework_tool --versions # Framework only
sudo ectool version # ChromeOS EC only
# Check that EC events and battery reporting still look normal
sudo dmesg | grep -i "ACPI: EC"
cat /sys/class/power_supply/BAT0/uevent
Then test the things the EC owns: keyboard, touchpad, lid sleep and wake, charging LED, fans under load and charge limits if you use them.
A note on writing to the EC directly
Linux has a debug module, ec_sys, that exposes the 256 byte EC address space through debugfs. Write access is off unless you load it with write_support=1, and the kernel's own description of that parameter reads "Dangerous, reboot and removal of battery may be needed." Community tools also write EC registers to change fan or charge behaviour. Writing arbitrary EC registers can change charging or thermal behaviour in ways the vendor never tested. Treat this as a developer feature: do not use write access on a machine you depend on, and never write to EC addresses based on values copied from a different model.
Common mistakes
- Assuming "BIOS update" means only UEFI. Many system firmware capsules also update the EC, and sometimes PD controllers. Read the release notes so you know what changed and what to test.
- Updating on battery alone. An EC or firmware update that loses power can leave the EC unable to power the system on. Use AC power and a charged battery.
- Interrupting what looks like a hang. EC updates often include a full power off with a dark screen. Holding the power button at that moment is the classic way to brick a laptop.
- Treating
ectooloutput as universal.ectoolspeaks ChromeOS host commands. On a laptop with a different EC it will fail or mislead. Use the tool that matches the EC. - Writing EC registers from a forum post. Register maps are per model and per firmware version. A value that sets fan speed on one laptop can change charging on another.
- Ignoring battery packs. Third party or refurbished packs carry their own gas gauge firmware and calibration. A pack that misreports state can confuse the EC's charging logic.
- Assuming open source means verifiable on the device. Open EC source tells you what the code should do. To know what runs, you need reproducible builds, version reporting and a verified boot chain such as ChromeOS software sync.
- Forgetting the EC in asset inventory. Fleet inventories often track BIOS versions but not EC or PD controller versions, so known EC fixes are hard to confirm across a fleet.
- Disabling write protection and forgetting to re-enable it. On ChromeOS devices, development workflows require turning off write protect and software sync. Leave either off and you lose the protections described above.
FAQ
What is an embedded controller in a laptop?
It is a small microcontroller on the mainboard that runs separately from the main processor. It scans the keyboard, manages battery charging, controls fans, reads the lid switch and power button, drives LEDs and sequences power so the main processor can start. It runs whenever the battery or charger supplies power.
Is the EC the same as the BIOS or UEFI?
No. UEFI firmware runs on the main processor and starts the operating system. The EC is a separate chip with separate firmware. They are often updated together because vendors package the EC image inside the same system firmware capsule.
How do I check my EC firmware version on Linux?
Start with fwupdmgr get-devices, which shows system firmware and any separately exposed devices. On ChromeOS EC hardware use ectool version; on Framework laptops use framework_tool --versions. Otherwise check the firmware setup screen or the vendor's tool.
Can a bad EC firmware update brick a laptop?
It can. If the EC cannot run valid firmware, it may never power on the main processor. Some designs keep a protected recovery image, such as the ChromeOS RO image, and others need an external programmer. That is why updates should run on AC power and never be interrupted.
Is EC firmware open source?
Sometimes. The ChromeOS EC is open source, with Zephyr based builds for Chromebook designs since roughly July 2021. Framework maintains a downstream fork of it, and System76 publishes GPLv3 EC firmware for its laptops. Most other laptop EC firmware is closed.
Why does my laptop fully power off after a BIOS update?
When the update includes EC firmware, the EC has to restart to run the new code. Because the EC controls power, restarting it cuts power to the whole system, so you see a full power off instead of a normal reboot.
Can malware infect the embedded controller?
Researchers showed in 2010 and 2011 that modified EC and keyboard controller code can run out of the operating system's sight. Whether a given laptop is exposed depends on how its EC firmware is protected and updated: signed updates, write protection and verification at boot all reduce the risk. NIST SP 800-193 describes these protections.
What is EC software sync on a Chromebook?
The Chromebook's main firmware carries a copy of the EC's read/write image. At boot, the host checks the EC's RW firmware hash against that copy and re-flashes the EC if they differ. Because the main firmware is verified by vboot, the EC image inherits that chain of trust.
How does the operating system talk to the embedded controller?
Through the ACPI embedded controller interface: a status and command port and a data port, with read, write, burst and query commands. When the EC raises an event, the OS sends the query command and runs the matching _Qxx ACPI method.
Does the battery have its own firmware?
Yes. Smart battery packs contain a gas gauge microcontroller with firmware and calibration data. It reports voltage, current, temperature and charge, and asks the charger for a charging voltage and current using commands from the Smart Battery Data Specification.
Where Safeguard fits
Safeguard does not scan EC images, battery firmware or flash chips, does not read EC versions from laptops and does not manage devices. The fit is with the software around firmware. Open source EC firmware is ordinary source code: the ChromeOS EC tree, its Zephyr dependency, the Framework fork and System76's EC (whose setup script installs a Rust toolchain) all pull in libraries, toolchains and build containers. So do the in house tools many teams write to collect firmware versions from a fleet, parse fwupd output or stage updates. Those repositories and containers need the same dependency hygiene as any application.
An EC fix still has to come from the laptop maker, and the update still has to be applied on each device. What you can control is the code you build around it: firmware build trees you maintain, update tooling and inventory scripts. That is where the steps below apply.
Fix it without waiting for upstream
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.
3. Gold Registry: start from components that are already fixed
registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | The Gold scan GitHub Action in CI, plus Safeguard policies and gates |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch (early access) |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
See how Safeguard would help
The demos below show Safeguard on ordinary software projects, not on EC firmware or laptops. They apply to the repositories around EC work: an open EC tree you build, its build container, and the scripts that collect firmware versions or stage updates. Safeguard can scan those with safeguard scan --dir ., --image for a container image, or --sbom for an SBOM file you already have, and it writes results as JSON under ./output.
The first demo is a real Safeguard CLI session. After install, safeguard opens the interactive terminal, you ask it to fix the lodash CVE in a repository, and it reads the finding and advisory, asks before each command, edits package.json to lodash 4.17.21, runs npm install and npm test with your approval, prints a summary and pushes nothing. It ends with /permissions, /model and /scan. The same ask, approve and test loop fits a firmware tooling repository where every change should be reviewed before it runs.
Click through it at your own pace, or open it full screen.
Firmware build machines are often kept apart from the general network. The local runner demo shows how to set up the runner on your own machine, approve it with its device code, and then scan from the terminal. A runner on a build host can scan the EC build tree and the containers that live there.
Click through it at your own pace, or open it full screen.
If your team uses Claude, the third demo shows how to connect Claude to the Safeguard MCP server with OAuth and choose which tools Claude can use. An engineer can then ask about known vulnerabilities in the projects that hold your firmware build and fleet update tooling, using only the tools you allowed.
Click through it at your own pace, or open it full screen.
To try it on your own repositories, download Safeguard and follow the CLI documentation.
Quick check
A laptop's lid closes and the OS goes to sleep. Which part of the ACPI EC interface carried that news?
The EC set its SCI_EVT status flag and raised a general purpose event. The OS sent the query command (0x84), the EC returned an event number, and the OS ran the matching _Qxx ACPI method, which notified the lid device.
On a Chromebook, the EC's RW firmware does not match the copy in the main firmware at boot. What happens?
EC software sync re-flashes the EC's RW section from the copy carried in the verified main firmware, then the EC jumps to the new RW image. The RO image, locked at the factory, is what boots first and asks the host to check the hash.
Sources
- ChromeOS EC README (legacy Chrome EC)
- ChromeOS EC: Zephyr EC introduction
- ChromeOS EC: Application Processor to EC communication
- ChromeOS EC: Firmware write protection
- ChromeOS EC: EC acronyms and technologies
- ChromeOS EC: Configuring the EC for low battery startup
- Chromium OS design docs: Firmware Boot and Recovery
- Framework EmbeddedController repository
- Framework framework-system tool README
- Framework framework-system EXAMPLES
- System76 EC repository
- System76 EC: supported embedded controllers
- System76 EC: flashing firmware
- Linux kernel ACPI embedded controller driver, drivers/acpi/ec.c
- Linux kernel ACPI EC debugfs module, drivers/acpi/ec_sys.c
- Linux kernel ABI: sysfs-firmware-acpi
- ChromeOS EC: ectool source, util/ectool.cc
- Linux kernel documentation: ACPI support (firmware guide)
- SBS Implementers Forum: SBS specifications
- Smart Battery Data Specification, Revision 1.1 (11 December 1998)
- NIST SP 800-193, Platform Firmware Resiliency Guidelines (May 2018)
- NIST SP 800-193 full text (PDF)
- fwupd project
- fwupd UEFI capsule plugin
- fwupd ChromeOS EC plugin
- Alexandre Gazet, "Sticky fingers & KBC Custom Shop", SSTIC 2011
- Charlie Miller, "Battery Firmware Hacking" white paper, Black Hat USA 2011
Last reviewed: 24 October 2026. EC update methods, open source EC branches and fwupd device support change between releases and models; check your laptop maker's release notes and the project repositories for current details.