blob: cb511765638f2ae6e3d8bebd885a6526d4b04ddb [file] [log] [blame] [edit]
# Copyright 2021 The Chromium OS Authors. All rights reserved.
# 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.
flash_extra_flags_futility: extra flags to flash with futility.
flash_extra_flags_flashrom: extra flags to flash with flashrom.
cros_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)