blob: 6284e0af4b8ddc50b3b2c216924a5e7da13a45ab [file] [log] [blame] [edit]
# Copyright 2021 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""AP Firmware Config related functionality.
This module holds the firmware config objects, provides functionality to read
the config from ap_firmware_config modules, and export it into JSON.
"""
import json
import logging
import os
from pathlib import Path
import sys
from typing import List, NamedTuple, Optional
from chromite.lib.firmware import ap_firmware_config
from chromite.lib.firmware import servo_lib
_CONFIG_BUILD_WORKON_PACKAGES = "BUILD_WORKON_PACKAGES"
_CONFIG_BUILD_PACKAGES = "BUILD_PACKAGES"
class Error(Exception):
"""Base error class for the module."""
class FirmwareConfig(NamedTuple):
"""Stores firmware config for a specific board and a specific servo/ssh.
Attributes:
dut_control_on: 2d array formatted like
[["cmd1", "arg1", "arg2"], ["cmd2", "arg3", "arg4"]]
with commands that need to be ran before flashing,
where cmd1 will be run before cmd2.
dut_control_off: 2d array formatted like
[["cmd1", "arg1", "arg2"], ["cmd2", "arg3", "arg4"]]
with commands that need to be ran after flashing,
where cmd1 will be run before cmd2.
programmer: programmer argument (-p) for flashrom and futility.
force_flashrom: force use of flashrom instead of futility.
flash_extra_flags_futility: extra flags to flash with futility.
flash_extra_flags_flashrom: extra flags to flash with flashrom.
workon_packages: packages to cros-workon before building.
build_packages: packages to build.
"""
dut_control_on: List[List[str]]
dut_control_off: List[List[str]]
programmer: str
force_flashrom: bool
flash_extra_flags_futility: List[str]
flash_extra_flags_flashrom: List[str]
workon_packages: List[str]
build_packages: List[str]
def get_config(
build_target_name: str, servo: Optional[servo_lib.Servo]
) -> FirmwareConfig:
"""Return config for a given build target and servo/ssh.
Args:
build_target_name: Name of the build target, e.g. 'dedede'.
servo: servo: The servo connected to the target DUT. None for SSH.
"""
module = ap_firmware_config.get(build_target_name, fallback=True)
workon_packages = getattr(module, _CONFIG_BUILD_WORKON_PACKAGES, None)
build_packages = getattr(
module, _CONFIG_BUILD_PACKAGES, ["chromeos-bootimage"]
)
if servo:
dut_control_on, dut_control_off, programmer = module.get_config(servo)
force_flashrom = getattr(module, "DEPLOY_SERVO_FORCE_FLASHROM", False)
# Some servo variables are set to a different value by other programs.
# Reset them to the default and then append with variables from the
# config to avoid overriding config.
reset_dut_control_on = [["ec_uart_timeout:10"]]
dut_control_on = reset_dut_control_on + dut_control_on
else:
dut_control_on = []
dut_control_off = []
programmer = "host"
force_flashrom = getattr(module, "DEPLOY_SSH_FORCE_FLASHROM", False)
flash_extra_flags_futility = []
flash_extra_flags_flashrom = []
if hasattr(module, "is_fast_required") and servo:
if module.is_fast_required(True, servo):
flash_extra_flags_futility += ["--fast"]
if module.is_fast_required(False, servo):
flash_extra_flags_flashrom += ["-n"]
if hasattr(module, "deploy_extra_flags_futility"):
flash_extra_flags_futility += module.deploy_extra_flags_futility(servo)
if hasattr(module, "deploy_extra_flags_flashrom"):
flash_extra_flags_flashrom += module.deploy_extra_flags_flashrom(servo)
return FirmwareConfig(
dut_control_on,
dut_control_off,
programmer,
force_flashrom,
flash_extra_flags_futility,
flash_extra_flags_flashrom,
workon_packages,
build_packages,
)
def export_config_as_json(
build_targets: Optional[List[str]] = None,
output_path: Optional[str] = None,
serial: str = None,
):
"""Exports config for all board:servo pairs in JSON.
Args:
build_targets: Names of the boards, e.g. ['dedede']. None for all
boards.
output_path: Name of the output file. None for stdout.
serial: Serial number of the DUT. If None, %s will be used.
"""
if not serial:
serial = "%s"
boards = []
if build_targets:
boards = build_targets
else:
# Get the board list from config python modules in ap_firmware_config
ap_firmware_config_path = (
Path(os.path.dirname(__file__)) / "ap_firmware_config"
)
for p in ap_firmware_config_path.glob("*.py"):
if not p.is_file():
continue
if p.name.startswith("_"):
continue
# Remove paths, leaving only filenames, and remove .py suffixes.
boards.append(p.with_suffix("").name)
boards.sort()
if output_path:
logging.info("Dumping AP config to %s", output_path)
logging.info("List of boards: %s", ", ".join(boards))
logging.info("List of servos: %s", ", ".join(servo_lib.VALID_SERVOS))
output = {}
failed_board_servos = {}
for board in boards:
output[board] = {}
for servo_version in servo_lib.VALID_SERVOS + ("ssh",):
servo = None
if servo_version != "ssh":
servo = servo_lib.Servo(servo_version, serial)
# get_config() call is expected to fail for some board:servo pairs.
# Disable logging to avoid inconsistent error messages from config
# modules' get_config() calls.
logging.disable(logging.CRITICAL)
try:
conf = get_config(board, servo)
except servo_lib.UnsupportedServoVersionError:
failed_board_servos.setdefault(board, []).append(servo_version)
continue
finally:
# Reenable logging.
logging.disable(logging.NOTSET)
output[board][servo_version] = {
"dut_control_on": conf.dut_control_on,
"dut_control_off": conf.dut_control_off,
"programmer": conf.programmer,
"force_flashrom": conf.force_flashrom,
"flash_extra_flags_futility": conf.flash_extra_flags_futility,
"flash_extra_flags_flashrom": conf.flash_extra_flags_flashrom,
}
for board, servos in failed_board_servos.items():
logging.info("[%s] skipping servos %s", board, ", ".join(servos))
if not output_path:
# Print to stdout.
json.dump(
output, sys.stdout, ensure_ascii=False, indent=2, sort_keys=True
)
else:
# Write to a file.
with open(output_path, "w", encoding="utf-8") as output_file:
json.dump(
output,
output_file,
ensure_ascii=False,
indent=2,
sort_keys=True,
)