blob: 4963d11dc4c7d3fa51e97c6a09d01252296aec6a [file] [log] [blame]
# Copyright (c) 2013 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.
"""Checks eMMC firmware version using the CID register values from sysfs.
This depends on the kernel exposing the CID fields directly in sysfs, this
enables future proofing by leaving the CID parsing to the kernel. The CID
register is only read for the purposes of logging.
If the test fails, then the test displays an error message and hangs forever.
Values used in this test, these are defined by JEDEC:
CID: Card IDentification register, 128 bit wide register readable from a
standard eMMC device providing basic identification information.
MID: Manufacturer ID, 8 bit field in CID register, unique to a given eMMC
vendor.
PNM: Product name, 48 bit wide field in CID register, a 6 ASCII character
string providing the name of a eMMC device.
PRV: Product revision, 8 bit field in CID register, a vendor specific value
typically representing a firmware version.
"""
import logging
import os
import re
import unittest
import factory_common # pylint: disable=unused-import
from cros.factory.test import event_log
from cros.factory.test.i18n import test_ui as i18n_test_ui
from cros.factory.test import test_ui
from cros.factory.test import ui_templates
from cros.factory.utils.arg_utils import Arg
class eMMCCheckFWVersionTest(unittest.TestCase):
ARGS = [
Arg('valid_versions', list, 'A list of tuples, specifying the MID, PNM '
'and a regex for the versions supported for that MID/PNM.'),
Arg('cid_path', str, 'Path to CID value',
default='/sys/devices/dw_mmc.0/mmc_host/mmc0/mmc0:0001/cid'),
Arg('mid_path', str, 'Path to MID value',
default='/sys/devices/dw_mmc.0/mmc_host/mmc0/mmc0:0001/manfid'),
Arg('pnm_path', str, 'Path to PNM value',
default='/sys/devices/dw_mmc.0/mmc_host/mmc0/mmc0:0001/name'),
Arg('prv_path', str, 'Path to PRV value',
default='/sys/devices/dw_mmc.0/mmc_host/mmc0/mmc0:0001/prv'),
Arg('emmc_updater_available', bool, 'Boolean for if an eMMC FW update '
'utility is available.', default=False)
]
def _ValidatePRVField(self, mid, pnm, prv, valid_versions):
"""Validate the PRV field for a given manufacturer.
Args:
mid: string of the hex representation of the MID value
pnm: string of the PNM value
prv: string of the hex representation of the PRV value
valid_versions: A list of tuples, specifying the MID, PNM, and a regex
for the versions supported for that MID/PNM.
Returns:
Boolean, true if FW revision is valid, false if not.
Raises:
ValueError if the MID value is not found in the test valid_versions
AssertionErrror if prv length is not 2
# Doctests
>>> from cros.factory.utils.arg_utils import Args
>>> test = eMMCCheckFWVersionTest()
>>> test._ValidatePRVField("00", "PARTNM", "01", [("00", "PARTNM", r"..")])
True
>>> test._ValidatePRVField("00", "PARTNM", "10", [("00", "PARTNM", r"2.")])
False
>>> test._ValidatePRVField("00", "BADPRT", "01", [("00", "PARTNM", r"..")])
Traceback (most recent call last):
...
ValueError: MID 00 PNM BADPRT not found in test list, wrong eMMC?
>>> test._ValidatePRVField("99", "PARTNM", "01", [("00", "PARTNM", r"..")])
Traceback (most recent call last):
...
ValueError: MID 99 PNM PARTNM not found in test list, wrong eMMC?
>>> test._ValidatePRVField("00", "PART", "123", [("00", "PART", r"..")])
Traceback (most recent call last):
...
AssertionError: Invalid prv length
"""
for valid_mid, valid_pnm, regex in valid_versions:
if valid_mid == mid and valid_pnm == pnm:
self.assertTrue(len(prv) == 2, 'Invalid prv length')
if re.match(regex, prv):
logging.info('The eMMC firmware version %s is correct.', prv)
return True
else:
logging.info('The eMMC FW version %s does not match %s.', prv, regex)
return False
raise ValueError('MID %s PNM %s not found in test list, wrong eMMC?' %
(mid, pnm))
def runTest(self):
self.assertTrue(os.path.exists(self.args.cid_path), 'cid_path %s is not '
'found, bad path?' % (self.args.cid_path))
self.assertTrue(os.path.exists(self.args.mid_path), 'mid_path %s is not '
'found, bad path?' % (self.args.mid_path))
self.assertTrue(os.path.exists(self.args.pnm_path), 'pnm_path %s is not '
'found, bad path?' % (self.args.pnm_path))
self.assertTrue(os.path.exists(self.args.prv_path), 'prv_path %s is not '
'found, bad path?' % (self.args.prv_path))
cid = open(self.args.cid_path).read().strip()
mid = open(self.args.mid_path).read().strip()[-2:]
pnm = open(self.args.pnm_path).read().strip()
prv = open(self.args.prv_path).read().strip()[-2:]
logging.info('Raw CID value: %s', cid)
logging.info('MID: %s, PNM: %s, PRV: %s', mid, pnm, prv)
event_log.Log('emmc_obtained', cid=cid, mid=mid, pnm=pnm, prv=prv)
if self._ValidatePRVField(mid, pnm, prv, self.args.valid_versions):
return # Pass the test
if self.args.emmc_updater_available:
ui = test_ui.UI()
template = ui_templates.OneSection(ui)
template.SetTitle(
i18n_test_ui.MakeI18nLabel('eMMC Firmware Version Incorrect'))
template.SetState(
'<div class=test-status-failed style="font-size: 150%">'
+ i18n_test_ui.MakeI18nLabel(
'The eMMC firmware version ({version}) is incorrect. '
'<br>Please run the eMMC firmware update tool.',
version=prv) + '</div>')
ui.Run() # Forever
else:
self.fail('The eMMC firmware version (%s) is incorrect. However, no '
'update is currently available.' % prv)