blob: 484139d66ad7b7dbb8e68df800ea6f928cbe3f79 [file] [log] [blame]
# Copyright (c) 2012 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 re
from autotest_lib.client.bin import test, utils
from autotest_lib.client.common_lib import error
FLASHROM_ACCESS_FAILED_TOKEN = ('Could not fully verify due to access error, '
class firmware_LockedME(test.test):
# Needed by autotest
version = 1
# Temporary file to read BIOS image into. We run in a tempdir anyway, so it
# doesn't need a path.
BIOS_FILE = 'bios.bin'
def flashrom(self, ignore_status=False, args=()):
"""Run flashrom, expect it to work. Fail if it doesn't"""
extra = ['-p', 'host'] + list(args)
return'flashrom', ignore_status=ignore_status, args=extra)
def determine_sw_wp_status(self):
"""Determine software write-protect status."""'Check that SW WP is enabled or not...')
flashrom_result = self.flashrom(args=('--wp-status',))'The above flashrom command returns.... %s',
if (("disabled" in flashrom_result.stdout) and
("start=0x00000000, len=0x0000000" in flashrom_result.stdout)):
return False
return True
def has_ME(self):
"""See if we can detect an ME.
FREG* is printed only when HSFS_FDV is set, which means the descriptor
table is valid. If we're running a BIOS without a valid descriptor this
step will fail. Unfortunately, we don't know of a simple and reliable
way to identify systems that have ME hardware.
"""'See if we have an ME...')
r = self.flashrom(args=('-V',))
return r.stdout.find("FREG0") >= 0
def try_to_rewrite(self, sectname):
"""If we can modify the ME section, restore it and raise an error."""'Try to write section %s...', sectname)
size = os.stat(sectname).st_size'dd', args=('if=/dev/urandom', 'of=newdata',
'count=1', 'bs=%d' % (size)))
r = self.flashrom(args=('-V', '-w', self.BIOS_FILE,
'-i' , '%s:newdata' % (sectname),
if (not r.exit_status and
FLASHROM_ACCESS_FAILED_TOKEN not in r.stdout):'Oops, it worked! Put it back...')
self.flashrom(args=('-w', self.BIOS_FILE,
'-i', '%s:%s' % (sectname, sectname),
raise error.TestFail('%s is writable, ME is unlocked' % sectname)
def check_manufacturing_mode(self):
"""Fail if manufacturing mode is not found or enbaled."""
# See if coreboot told us that the ME is still in Manufacturing Mode.
# It shouldn't be. We have to look only at the last thing it reports
# because it reports the values twice and the first one isn't always
# reliable.'Check for Manufacturing Mode...')
last = None
with open('/sys/firmware/log') as infile:
for line in infile:
if'ME: Manufacturing Mode', line):
last = line
if last is not None and last.find("YES") >= 0:
raise error.TestFail("The ME is still in Manufacturing Mode")
def check_region_inaccessible(self, sectname):
"""Test and ensure a region is not accessible by host CPU."""
# flashrom should have read the section as all 0xff's. If not,
# the ME is not locked.'%s should be all 0xff...' % sectname)
with open(sectname, 'rb') as f:
for c in
if c != chr(0xff):
err_string = "%s was readable by flashrom" % sectname
raise error.TestFail(err_string)
# See if it is writable.
def run_once(self, expect_me_present=True):
"""Fail unless the ME is locked.
@param expect_me_present: False means the system has no ME.
cpu_arch = utils.get_cpu_arch()
if cpu_arch == "arm":
raise error.TestNAError('This test is not applicable, '
'because an ARM device has been detected. '
'ARM devices do not have an ME (Management Engine)')
cpu_family = utils.get_cpu_soc_family()
if cpu_family == "amd":
raise error.TestNAError('This test is not applicable, '
'because an AMD device has been detected. '
'AMD devices do not have an ME (Management Engine)')
# If sw wp is on, and the ME regions are unlocked, they won't be
# writable so will appear locked.
if self.determine_sw_wp_status():
raise error.TestFail('Software wp is enabled. Please disable '
'software wp prior to running this test.')
# See if the system even has an ME, and whether we expected that.
if self.has_ME():
if not expect_me_present:
raise error.TestFail('We expected no ME, but found one anyway')
if expect_me_present:
raise error.TestNAError("No ME found. That's probably wrong.")
else:'We expected no ME and we have no ME, so pass.')
# Make sure manufacturing mode is off.
# Read the image using flashrom.
self.flashrom(args=('-r', self.BIOS_FILE))
# Use 'IFWI' fmap region as a proxy for a device which doesn't
# have a dedicated ME region in the boot media.
r ='dump_fmap', args=('-p', self.BIOS_FILE))
is_IFWI_platform = r.stdout.find("IFWI") >= 0
# Get the bios image and extract the ME components'Pull the ME components from the BIOS...')
dump_fmap_args = ['-x', self.BIOS_FILE, 'SI_DESC']
inaccessible_sections = []
if is_IFWI_platform:
dump_fmap_args.extend(inaccessible_sections)'dump_fmap', args=tuple(dump_fmap_args))
# So far, so good, but we need to be certain. Rather than parse what
# flashrom tells us about the ME-related registers, we'll just try to
# change the ME components. We shouldn't be able to.
for sectname in inaccessible_sections:
# Okay, that's about all we can try. Looks like it's locked.