| # Reducing the EC image size |
| |
| The EC ToT codebase continues grows as new features are added and for bug fixes. |
| This puts pressure on older boards that have limited flash space remaining. This |
| document provides some tips for reducing the EC image size. |
| |
| [TOC] |
| |
| ## Checking the EC image footprint |
| |
| The EC codebase supports two build types: |
| |
| 1. `cros-ec` builds are the legacy EC images built using Make (e.g. `make |
| BOARD=volteer`) |
| 1. `zephyr-ec` builds are the EC images built using the Zephyr RTOS kernel |
| using zmake/Cmake (e.g. `zmake build herobrine`) |
| |
| ### Checking a single cros-ec build |
| |
| Building a single cros-ec board using `make BOARD=<board> -j` reports the the |
| number of bytes free in flash and RAM for both the RO and RW images. An example |
| from building the juniper board is shown below. |
| |
| ``` |
| $ make BOARD=juniper -j |
| ... |
| *** 668 bytes in flash and 10308 bytes in RAM still available on juniper RO **** |
| *** 3224 bytes in flash and 7460 bytes in RAM still available on juniper RW **** |
| ``` |
| |
| ### Checking all cros-ec builds |
| |
| Running `make buildall -j` shows a summary of the three boards with the smallest |
| RO flash footprint, FW flash footprint, and RW RAM footprint. |
| |
| ``` |
| $ make buildall -j |
| ... |
| buildall completed successfully! |
| Smallest free spaces in RO flash (bytes): |
| servo_v4 : 104 |
| scarlet : 108 |
| mushu : 160 |
| Smallest free spaces in RW flash (bytes): |
| mushu : 96 |
| bobba : 232 |
| trondo : 376 |
| Tightest boards' RW RAM images, bytes free: |
| whiskers : 244 |
| minimuffin: 284 |
| zinger : 284 |
| ``` |
| |
| ### Checking a single zephyr-ec build |
| |
| By default, `zmake` will display the flash and SRAM usage of the board. |
| |
| ``` |
| $ zmake build herobrine |
| ... |
| Building herobrine:ro: /usr/bin/ninja -C /mnt/host/source/src/platform/ec/build/zephyr/herobrine/build-ro |
| -- git describe warned: warning: tag 'upstream/v2.7.99' is externally known as 'v2.7.99' |
| -- Zephyr version: 3.0.99 (/mnt/host/source/src/third_party/zephyrproject/zephyr), build: v2.7.99-5035-ga17c05c7228e |
| Memory region Used Size Region Size %age Used |
| FLASH: 219920 B 256 KB 83.89% |
| SRAM: 49688 B 64 KB 75.82% |
| IDT_LIST: 0 GB 2 KB 0.00% |
| Building herobrine:rw: /usr/bin/ninja -C /mnt/host/source/src/platform/ec/build/zephyr/herobrine/build-rw |
| -- git describe warned: warning: tag 'upstream/v2.7.99' is externally known as 'v2.7.99' |
| -- Zephyr version: 3.0.99 (/mnt/host/source/src/third_party/zephyrproject/zephyr), build: v2.7.99-5035-ga17c05c7228e |
| Memory region Used Size Region Size %age Used |
| FLASH: 219920 B 256 KB 83.89% |
| SRAM: 49688 B 64 KB 75.82% |
| IDT_LIST: 0 GB 2 KB 0.00% |
| ``` |
| |
| Note, that the flash region size listed above represents the total flash |
| available on the EC. The actual available region size is only half the reported |
| value in order to store two images (RO+RW). |
| |
| #### Other Zephyr utilities |
| |
| The CMake system utilized by Zephyr provides two build targets |
| [`rom_report` and `ram_report`][3] which generate a list of all the compiled |
| objects in tabular form. This can be useful for identifying particular modules |
| that contribute to the image size. |
| |
| **Build the target board**: |
| |
| ```bash |
| (chroot) $ zmake build --clobber helipilot |
| ``` |
| |
| **Generate the ROM report for the RO image**: |
| |
| ```bash |
| (chroot) $ ninja -C ~/chromiumos/src/platform/ec/build/zephyr/helipilot/build-ro rom_report |
| ``` |
| |
| **Generate the ROM report for the RW image**: |
| |
| ```bash |
| (chroot) $ ninja -C ~/chromiumos/src/platform/ec/build/zephyr/helipilot/build-rw rom_report |
| ``` |
| |
| ## Checking a board's config |
| |
| If you want to see what configs are enabled for a given board, use the |
| `print-configs` `Makefile` target: |
| |
| ```shell |
| $ make BOARD=<BOARD> print-configs |
| ``` |
| |
| You can also open the `./build/<BOARD>/.config` file that is generated after |
| building the board with `make BOARD=<BOARD>`. |
| |
| ## Disable console commands |
| |
| The lowest hanging fruit for reducing the EC image size is by disabling console |
| commands that provide debug information only and don't impact the user or the |
| automated testing. Any console command that is not used by the FAFT tests and |
| suites is safe to disable in the EC images. |
| |
| For cros-ec builds, add `#undef CONFIG_CMD_<name>` to the board.h or baseboard.h |
| file to disable the console command. |
| |
| For zephyr-ec builds, add `CONFIG_PLATFORM_EC_CONSOLE_CMD_<name>=n` to the board |
| prj.conf file to disable the console command. |
| |
| * TODO: Create new CONFIG/Kconfig option that disables all console commands |
| not required by FAFT. |
| |
| <!-- mdformat off(Don't format table) --> |
| |
| | Used by FAFT | config.h option | Console commands | Notes | |
| |:---|:---|:---|:---| |
| | | CONFIG_CMD_ACCELS | `accelrange`<br>`accelres`<br>`accelrate`<br>`accelread`<br>`accelinit`<br>`accelinfo` | | |
| | | CONFIG_CMD_ACCELSPOOF | `accelspoof` | | |
| | | CONFIG_CMD_ACCEL_FIFO | `fiforead` | | |
| | | CONFIG_CMD_ACCEL_INFO | `accelinfo` | | |
| | | CONFIG_CMD_ADC | `adc` | Note firmware.ECADC uses the `temps` command. | |
| | | CONFIG_CMD_ALS | `als` | | |
| | | CONFIG_CMD_APTHROTTLE | `apthrottle` | | |
| | | CONFIG_CMD_AP_RESET_LOG |??? | | |
| | | CONFIG_CMD_BATDEBUG | `fgunseal`<br>`fgseal`<br>`fginit`<br>`fgprobe`<br>`fgrd`<br>`fgcmd`<br>`fcmdrd` | | |
| | | CONFIG_CMD_BATTFAKE | `battfake` | | |
| | | CONFIG_CMD_BATT_MFG_ACCESS | `battmfgacc` | | |
| | | CONFIG_CMD_CBI | `cbi` | firmwareECCbiEeprom uses `ectool` on AP to test CBI | |
| | x | CONFIG_CMD_CHARGEN | `chargen` | Used by firmware_Cr50CCDUartStress, included in faft_ccd, faft_cr50_prepvt, and faft_cr50_pvt suites | |
| | | CONFIG_CMD_CHARGER | `bd9995x`<br>`sy21612` | | |
| | | CONFIG_CMD_CHARGER_ADC_AMON_BMON | `amonbmon` | | |
| | | CONFIG_CMD_CHARGER_DUMP | `charger_dump` | | |
| | | CONFIG_CMD_CHARGER_PROFILE_OVERRIDE | `fastcharge` | | |
| | | CONFIG_CMD_CHARGER_PROFILE_OVERRIDE_TEST | `fastchgtest` | | |
| | | CONFIG_CMD_CHARGE_SUPPLIER_INFO | `chgsup` | | |
| | | CONFIG_CMD_CHGRAMP | `chgramp` | | |
| | | CONFIG_CMD_CLOCKGATES | `clockgates` | | |
| | | CONFIG_CMD_COMXTEST | `comxtest` | | |
| | x | CONFIG_CMD_CRASH | `crash` | Used by TAST `crash.ECCrash`, FAFT `firmware.ECSharedMem` | |
| | | CONFIG_CMD_DEVICE_EVENT | `deviceevent` | | |
| | | CONFIG_CMD_DLOG | `dlog` | | |
| | | CONFIG_CMD_ECTEMP | `ectemp` | | |
| | | CONFIG_CMD_FASTCHARGE | `fastcharge` | Obsolete? use CONFIG_CMD_CHARGER_PROFILE_OVERRIDE? | |
| | | CONFIG_CMD_FLASH | `flasherase`<br>`flashwrite`<br>`flashread` | | |
| | x | CONFIG_CMD_FLASHINFO | `flashinfo` | Used by TAST `firmware.ECSize` | |
| | | CONFIG_CMD_FLASH_TRISTATE | `fpcapture`<br>`flash_tristate` | | |
| | | CONFIG_CMD_FLASH_WP | `flashwp` | | |
| | | CONFIG_CMD_FORCETIME | `forcetime` | | |
| | | CONFIG_CMD_FPSENSOR_DEBUG | `fpcapture`<br>`fpenroll`<br>`fpmatch`<br>`fpclear`<br>`fpmaintenance` | | |
| | | CONFIG_CMD_GETTIME | `gettime` | Used by Cr50 tests, not by FAFT EC | |
| | | CONFIG_CMD_GL3590 | `gl3590` | | |
| | | CONFIG_CMD_GPIO_EXTENDED | Adds options to `gpioget` and `gpioset`. | Should be renamed to CONFIG_GPOI_EXTENDED | |
| | | CONFIG_CMD_GPIO_POWER_DOWN | Not a valid config. | Should be CONFIG_GPIO_POWER_DOWN | |
| | | CONFIG_CMD_GT7288 | `gt7288_desc`<br>`gt7288_repdesc`<br>`gt7288_ver`<br>`gt7288_report` | | |
| | | CONFIG_CMD_HASH | `hash` | firmware.SoftwareSync uses `ectool echash` | |
| | x | CONFIG_CMD_HCDEBUG | `hcdebug` | firmware.BootTime looks at the console logs for HC | |
| | x | CONFIG_CMD_HOSTCMD | `hostcmd` | | |
| | | CONFIG_CMD_I2CWEDGE | `i2cwedge`<br>`i2cunwedge` | | |
| | | CONFIG_CMD_I2C_PROTECT | `i2cprotect` | | |
| | | CONFIG_CMD_I2C_SCAN | `i2cscan` | | |
| | | CONFIG_CMD_I2C_STRESS_TEST | `i2ctest` | | |
| | | CONFIG_CMD_I2C_STRESS_TEST_ACCEL | Not a console command | | |
| | | CONFIG_CMD_I2C_STRESS_TEST_ALS | Not a console command | | |
| | | CONFIG_CMD_I2C_STRESS_TEST_BATTERY | Not a console command | | |
| | | CONFIG_CMD_I2C_STRESS_TEST_CHARGER | Not a console command | | |
| | | CONFIG_CMD_I2C_STRESS_TEST_TCPC | `Not a console command | | |
| | | CONFIG_CMD_I2C_XFER | `i2cxfer` | firmware.ECCbiEeprom uses `ectool i2cxfer` which is not guarded by CONFIG_CMD_I2C_XFER | |
| | | CONFIG_CMD_I2C_XFER_RAW | | Adds options to `i2cxfer` | |
| | | CONFIG_CMD_IDLE_STATS | `idlestats` | | |
| | | CONFIG_CMD_INA | `ina` | | |
| | | CONFIG_CMD_JUMPTAGS | `jumptags` | | |
| | x | CONFIG_CMD_KEYBOARD | `8042`<br>`ksstate`<br>`kbpress` | Used by most all tests, and specifically `firmware.ECKeyboard` | |
| | | CONFIG_CMD_LEDTEST | `ledtest` | | |
| | | CONFIG_CMD_MCDP | `mcdp` | | |
| | | CONFIG_CMD_MD | `md` | | |
| | | CONFIG_CMD_MEM | | Not a console command - gates `md` and `rw` | |
| | | CONFIG_CMD_MFALLOW | `mfallow` | | |
| | | CONFIG_CMD_MMAPINFO | `mmapinfo` | | |
| | x | CONFIG_CMD_PD | `pd` | Used by FAFT PD, TAST `firmware.ECSystemLocked` | |
| | | CONFIG_CMD_PD_DEV_DUMP_INFO | | Not supported by TCPMv2 | |
| | | CONFIG_CMD_PD_FLASH | `pd flash` | Not supported by TCPMv2 | |
| | | CONFIG_CMD_PD_SRCCAPS_REDUCED_SIZE | `pd <port> srccaps` | Defining this reduces the verbosity of this command, saving bytes | |
| | | CONFIG_CMD_PECI | `peci` | | |
| | | CONFIG_CMD_PLL | `pll` | only used by lm4 chip | |
| | | CONFIG_CMD_POWERINDEBUG | `powerindebug` | | |
| | | CONFIG_CMD_POWERLED | `powerled` | | |
| | x | CONFIG_CMD_POWER_AP | `apreset`<br>`apshutdown` | Used by power_Monitoring.py | |
| | | CONFIG_CMD_PPC_DUMP | `ppc_dump` | | |
| | | CONFIG_CMD_PS2 | `ps2ench`<br>`ps2write` | Used only on NPCX | |
| | | CONFIG_CMD_PWR_AVG | `pwr_avg` | | |
| | | CONFIG_CMD_RAND | `rand` | Used only on STM32 | |
| | | CONFIG_CMD_REGULATOR | `ir357x` | | |
| | | CONFIG_CMD_RESET_FLAGS | `rflags` | | |
| | | CONFIG_CMD_RETIMER | `retimer` | | |
| | | CONFIG_CMD_RTC | `rtc` | | |
| | | CONFIG_CMD_RTC_ALARM | `rtc_alarm` | | |
| | | CONFIG_CMD_RW | `rw` | | |
| | | CONFIG_CMD_SCRATCHPAD | `scratchpad` | | |
| | | CONFIG_CMD_SEVEN_SEG_DISPLAY | `seg` | | |
| | | CONFIG_CMD_SHA256_TEST | `???` | | |
| | x | CONFIG_CMD_SHMEM | `shmem` | Used by firmware.ECSharedMem | |
| | | CONFIG_CMD_SLEEPMASK | `sleepmask` | Only used for Cr50 tests | |
| | | CONFIG_CMD_SLEEPMASK_SET | | Adds options to `sleepmask` | |
| | | CONFIG_CMD_SPI_FLASH | `spi_flasherase`<br>`spi_flashwrite`<br>`spi_flashread`<br>`spi_flash_rsr`<br>`spi_flash_wsr`<br>`spi_flash_wsr` | | |
| | | CONFIG_CMD_SPI_NOR | `spinorinfo`<br>`spinorerase`<br>`spinorwrite`<br>`spinorread` | | |
| | | CONFIG_CMD_SPI_XFER | `spixfer` | | |
| | x | CONFIG_CMD_SYSINFO | `sysinfo` | Used by firmware.ECSystemLocked | |
| | x | CONFIG_CMD_SYSJUMP | `sysjump` | Used by firmware.ECSharedMem | |
| | | CONFIG_CMD_SYSLOCK | `syslock` | | |
| | | CONFIG_CMD_TASKREADY | `taskready` | | |
| | | CONFIG_CMD_TASK_RESET | `taskreset` | | |
| | | CONFIG_CMD_TCPC_DUMP | `tcpci_dump` | | |
| | x | CONFIG_CMD_TEMP_SENSOR | `temps` | | |
| | | CONFIG_CMD_TIMERINFO | `timerinfo` | | |
| | | CONFIG_CMD_TYPEC | `typec` | | |
| | | CONFIG_CMD_USART_INFO | `usart_info` | | |
| | | CONFIG_CMD_USB_PD_CABLE | `pdcable` | | |
| | x | CONFIG_CMD_USB_PD_PE | `pe` | Doesn't appear to be used but might be by FAFT PD | |
| | x | CONFIG_CMD_WAITMS | `waitms` | firmware.ECWatchdog | | |
| |
| <!-- mdformat on --> |
| |
| ## Reduce or eliminate USB-C debugging |
| |
| The TCPM (Type-C Port manager) implementation is one of the more complex modules |
| implemented by the EC code. This module includes extensive debugging and is |
| enabled by default due to the value provided during both board bringup and on |
| production systems. |
| |
| The TCPM provides the following debug levels: |
| |
| * `DEBUG_DISABLE` (0) - Debugging disabled, no runtime messages displayed |
| * `DEBUG_LEVEL_1` (1) - Displays all the state transitions for the TC (Type-C) |
| and PE (Policy Engine) state machines |
| * `DEBUG_LEVEL_2` (2) - Displays the raw contents of received PD (Power |
| Delivery) packets, excluding PING packets |
| * `DEBUG_LEVEL_3` (3) - Enables debug messages in the PRL Also displays |
| received PING packets. |
| |
| When `CONFIG_USB_PD_DEBUG_LEVEL` is undefined, the EC allows runtime |
| configuration of the USB-C debug level using the `pd dump <level>` EC console |
| command. In this configuration, the strings from all debug levels are included |
| in the image. |
| |
| Enabling a fixed debug level removes runtime control of the debug level and also |
| removes the strings for the higher debug levels. |
| |
| For cros-ec builds, add the following to your board.h/baseboard.h file: |
| |
| ```c |
| #define CONFIG_USB_PD_DEBUG_LEVEL <level> |
| ``` |
| |
| For zephyr-ec builds, add the following to your prj.conf file: |
| |
| ``` |
| CONFIG_PLATFORM_EC_USB_PD_DEBUG_FIXED_LEVEL=y |
| CONFIG_PLATFORM_EC_USB_PD_DEBUG_LEVEL=<level> |
| ``` |
| |
| Approximate flash space savings from each fixed level setting: |
| |
| Fixed Debug Level | Relative Saving | Cumulative Saving |
| ----------------- | --------------- | ----------------- |
| Disabled | 0 | 0 |
| 3 | 100 bytes | 100 bytes |
| 2 | 500-600 bytes | 600-700 bytes |
| 1 | 100 bytes | 700-800 bytes |
| 0 | 2000 bytes | 2700-2800 bytes |
| |
| The recommended setting is setting the fixed debug level to `DEBUG_LEVEL_2` (2). |
| This adds details about received PD packets in the EC log stored by the kernel |
| and can help troubleshoot PD issues when a PD analyzer isn't available. |
| |
| It is not recommended to set the fixed debug level to `DEBUG_DISABLE` (0) on any |
| shipping firmware. |
| |
| ### TCPMv1 Configuration |
| |
| Many older platforms still use the legacy TCPMv1 (`CONFIG_USB_PD_TCPMV1`) |
| implementation. Specific to TCPMv1, the PD protocol state names can be removed |
| from the debug output by adding the following to the board.h/baseboard.h file. |
| |
| ```c |
| #undef CONFIG_USB_PD_TCPMV1_DEBUG |
| ``` |
| |
| This saves around 900 bytes of flash space. TCPMv2 does not currently provide an |
| equivalent configuration option, so there is also no Kconfig equivalent. |
| |
| ## Other optional features |
| |
| ### ASSERT() Calls |
| |
| By default, `ASSERT()` calls generate a console message of the following form: |
| |
| ``` |
| ASSERTION FAILURE '<expr>' in function() at file:line |
| ``` |
| |
| There are two options available that reduce the size of strings stored with the |
| `ASSERT()` calls. |
| |
| <!-- mdformat off(Don't format table) --> |
| |
| Description | cros-ec setting | zephyr-ec setting | Total Savings |
| :--- | :--- | :--- | :--- |
| Display only file and line number | `#define CONFIG_DEBUG_ASSERT_BRIEF` | `CONFIG_PLATFORM_EC_DEBUG_ASSERT_BRIEF=y` | 2000-2500 bytes |
| Disable all debug from ASSERT() calls.<br> EC is reset using a software breakpoint. | `#undef CONFIG_DEBUG_ASSERT_REBOOTS` | `CONFIG_PLATFORM_EC_DEBUG_ASSERT_REBOOTS=n`<br>`CONFIG_PLATFORM_EC_DEBUG_ASSERT_BREAKPOINT=y` | 3000-4000 bytes |
| |
| <!-- mdformat on --> |
| |
| It is not recommended to disable `CONFIG_PLATFORM_EC_DEBUG_ASSERT_REBOOTS` on |
| shipping firmware. |
| |
| ### Disable console help and history |
| |
| The help strings can be removed from the final build, saving about 5000 bytes of |
| flash space. The history command can also be disabled to save another 200 bytes |
| of flash space. |
| |
| For cros-ec builds, add `#undef CONFIG_CONSOLE_CMDHELP` and `#undef |
| CONFIG_CONSOLE_HISTORY` to the board.h/baseboard.h file. |
| |
| zephyr-ec builds use Zephyr's shell subsystem and by default enable the |
| `CONFIG_SHELL_MINIMAL` option. This option already disables shell help along |
| with many other non-critical features. Refer to the shell subsystem [Kconfig][2] |
| source file for the complete list of shell features than can be configured. |
| |
| ### Link time optimizaiton |
| |
| Link time optimization (LTO) is a feature of the linker to identify and remove |
| unused code. |
| |
| For cros-ec builds, LTO is enabled by adding this to the board.h/baseboard.h |
| file. |
| |
| ```c |
| #define CONFIG_LTO |
| ``` |
| |
| For zephyr-ec builds, LTO is enabled by default and is controlled with Kconfig. |
| |
| ``` |
| CONFIG_LTO=y |
| ``` |
| |
| ### CONFIG_CHIP_INIT_ROM_REGION |
| |
| The config option `CONFIG_CHIP_INIT_ROM_REGION` creates a new linker section to |
| store data that remains resident in ROM/flash at runtime. This reduces the |
| effective cros-ec image size by identifying data structures that do not need to |
| be copied into the code RAM section at startup. |
| |
| This option has the following requirements: |
| |
| 1. EC executes code from RAM |
| 2. The ROM/flash size is larger than 2 times the code RAM size. |
| 3. The RO code released for the board includes this |
| [change](https://crrev.com/c/2428566). |
| |
| The only EC chip that matches these prerequisites is the Nuvoton NPCX7. |
| |
| Due to the RO code requirement, take care before enabling this option for boards |
| released prior to 2021. |
| |
| If the above requirements are meant, add the following to the |
| board.h/baseboard.h file: |
| |
| ```c |
| #define CONFIG_CHIP_INIT_ROM_REGION |
| #define CONFIG_CHIP_DATA_IN_INIT_ROM |
| ``` |
| |
| These options are not supported for zephyr-ec builds. |
| |
| ### Enable short GPIO names |
| |
| The [GPIO macros](./configuration/gpio.md) defined by the board get stored as |
| descriptive strings for use with the `gpioget` and `gpioset` console commands. |
| |
| The names of the GPIOs can be shorted by enabling the |
| `CONFIG_COMMON_GPIO_SHORTNAMES` option. |
| |
| For example, the Kukui board defines this GPIO: |
| |
| ```c |
| GPIO(PMIC_FORCE_RESET_ODL, PIN(A, 2), GPIO_ODR_HIGH) |
| ``` |
| |
| Normally, the GPIO name is stored exactly as specified by the macro: |
| `PMIC_FORCE_RESET_ODL`. However, when `CONFIG_COMMON_GPIO_SHORTNAMES` is |
| defined, then the GPIO name is shortened to only include port and pin number: |
| `A2`. |
| |
| This option is currently only supported by the STM32 chip and it is not |
| supported by zephyr-ec builds. |
| |
| Note that there are some [FAFT tests][5] that rely on the GPIO name. If you |
| enable this option, you may also need to change firmware testing configuration |
| [file][6]. |
| |
| [2]:https://github.com/zephyrproject-rtos/zephyr/blob/main/subsys/shell/Kconfig |
| [3]:https://docs.zephyrproject.org/latest/guides/optimizations/tools.html |
| [5]:https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/main/src/go.chromium.org/tast-tests/cros/remote/bundles/cros/firmware/ec_usb_ports.go |
| [6]:https://chromium.googlesource.com/chromiumos/platform/fw-testing-configs/+/e2e9547e/volteer.json#26 |