blob: 51fb47c0c65a3cfc5405952c5112ad2ed4f10dd8 [file] [log] [blame]
# Copyright 2018 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.
import logging
import os
import tempfile
from autotest_lib.client.common_lib import error
from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
class platform_FlashErasers(FirmwareTest):
"""
Test that various erase functions work correctly by calling flashrom to
erase/write blocks of different sizes.
"""
version = 1
def run_cmd(self, command, checkfor=''):
"""
Log and execute command and return the output.
@param command: Command to execute on device.
@param checkfor: If not emmpty, fail test if checkfor not in output.
@returns the output of command as a list of strings.
"""
command = command + ' 2>&1'
logging.info('Execute %s', command)
output = self.faft_client.system.run_shell_command_get_output(command)
logging.info('Output >>> %s <<<', output)
if checkfor and checkfor not in '\n'.join(output):
raise error.TestFail('Expect %s in output of %s' %
(checkfor, '\n'.join(output)))
return output
def _get_section(self, bios, section):
"""Return start address and size of an fmap section.
@param bios: string, bios file name to retrieve fmap from
@param section: string, section name to look for
@return tuple of ints for start and size of the section.
"""
# Store temp results in the attributes dictionary; when the expected
# section name is found in the 'area_name:' field, the offset and size
# of the section would be stored in this dictionary.
attributes = {}
for line in [x.strip() for x in self.run_cmd('dump_fmap %s' % bios)]:
if not line:
continue
tokens = line.split()
if tokens[0] == 'area_name:' and tokens[1] == section:
return (int(attributes['area_offset:'], 16),
int(attributes['area_size:'], 16))
if len(tokens) > 1:
attributes[tokens[0]] = tokens[1]
raise error.TestFail('Could not find section %s in the fmap' % section)
def _create_test_blob(self, blob_name, blob_size):
"""On the DUT create a blob containing 0xff bytes of the requested size.
@param blob_name: string, name of the DUT file to save the blob in
@param blob_size: integer, size of the blob to prepare
"""
test_blob_data = ('%c' % 0xff) * blob_size
# Save it into a local file.
handle, local_file = tempfile.mkstemp()
try:
os.write(handle, test_blob_data)
os.close(handle)
# Copy the local file to the DUT.
self._client.send_file(local_file, blob_name)
finally:
# Delete local file.
os.remove(local_file)
def run_once(self, dev_mode=True):
"""Main method implementing test logic."""
# Find out which AP firmware section is active to determine which AP
# firmware section could be overwritten.
active_fw = self.run_cmd('crossystem mainfw_act')[0]
if active_fw == 'A':
section = 'RW_SECTION_B'
elif active_fw == 'B':
section = 'RW_SECTION_A'
else:
raise error.TestFail('Unexpected active fw %s' % active_fw)
dut_work_path = self.faft_client.updater.get_work_path()
# Sizes to try to erase.
test_sizes = (4096, 4096 * 2, 4096 * 4, 4096 * 8, 4096 * 16)
# Image read from the AP firmware flash chip.
bios_image = os.path.join(dut_work_path, 'bios_image')
self.run_cmd('flashrom -r %s' % bios_image)
# A blob of all ones to paste into the image.
test_blob = os.path.join(dut_work_path, 'test_blob')
self._create_test_blob(test_blob, max(test_sizes))
# The file to store the 'corrupted' image with all ones pasted.
junk_image = os.path.join(dut_work_path, 'junk_image')
# Find in fmap the AP firmware section which can be overwritten.
start, size = self._get_section(bios_image, section)
logging.info('Active firmware %s, alternative at %#x:%#x', active_fw,
start, start + size -1)
# Command to paste the all ones blob into the corrupted image.
dd_template = 'dd if="%s" of="%s" bs=1 conv=notrunc seek="%d"' % (
test_blob, junk_image, start)
for test_size in test_sizes:
logging.info('Verifying section of size %d', test_size)
self.run_cmd('cp %s %s' % (bios_image, junk_image))
# Set section in the 'junk' image to 'all erased'
dd_cmd = dd_template + ' count="%d"' % test_size
self.run_cmd(dd_cmd)
# Now program the corrupted image, this would involve erasing the
# section of test_size bytes.
self.run_cmd('flashrom -w %s --diff %s --fast-verify' %
(junk_image, bios_image))
# Now restore the image.
self.run_cmd('flashrom -w %s --diff %s' % (bios_image, junk_image))