普通文本  |  196行  |  7.28 KB

# Copyright (c) 2011 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, os, re

from autotest_lib.client.bin import utils
from autotest_lib.client.common_lib import error
from autotest_lib.server import test

_KERN_WARNING = 4

_WHITELIST_COMMON = [
    r"used greatest stack depth: \d+ bytes left",
    "Kernel-defined memdesc doesn't match the one from EFI!",
    "Use a HIGHMEM enabled kernel.",
   "GPT: Use GNU Parted to correct GPT errors.",
    r"GPT:\d+ != \d+",
    "GPT:Alternate GPT header not at the end of the disk.",
    "GPT:Primary header thinks Alt. header is not at the end of the disk.",
    r"GPT:partition_entry_array_crc32 values don't match: 0x[\da-f]+ !="
    " 0x[\da-f]+",
    r"Warning only \d+MB will be used.",
    "\[drm:intel_init_bios\] \*ERROR\* VBT signature missing",
    "i2c i2c-2: The new_device interface is still experimental and may change "
    "in a near future",
    "i915 0000:00:02.0: Invalid ROM contents",
    "industrialio: module is from the staging directory, the quality is "
    "unknown, you have been warned.",
    "pnp 00:01: io resource \(0x164e-0x164f\) overlaps 0000:00:1c.0 "
    "BAR 7 \(0x1000-0x1fff\), disabling",
    r"sd \d:\d:\d:\d: \[sd[a-z]\] Assuming drive cache: write through",
    "tsl[\da-z]+: module is from the staging directory, the quality is "
    "unknown, you have been warned.",
    "usb 1-2: unknown number of interfaces: 4",
]

_WHITELIST_TARGETS = {
    'Alex' : [
        r"CE: hpet increasing min_delta_ns to \d+ nsec",
        r"Measured \d+ cycles TSC warp between CPUs, turning off TSC clock.",
        "pci 0000:01:00.0: BAR 6: no parent found for of device "
        "\[0xffff0000-0xffffffff]",
        "tsl258x 2-0029: taos_get_lux data not valid",
        "usb 1-2: config 1 has an invalid interface number: 1 but max is 0",
        "usb 1-2: config 1 has no interface number 0",
        ],
    'Mario' : [
        "chromeos_acpi: failed to retrieve MLST \(5\)",
        r"btusb_[a-z]{4}_complete: hci\d urb [\da-f]+ failed to resubmit \(1\)",
        ]
}

""" Interesting fields from meminfo that we want to log
    If you add fields here, you must add them to the constraints
    in the control file
"""
_meminfo_fields = { 'MemFree'   : 'coldboot_memfree_mb',
                    'AnonPages' : 'coldboot_anonpages_mb',
                    'Buffers'   : 'coldboot_buffers_mb',
                    'Cached'    : 'coldboot_cached_mb',
                    'Active'    : 'coldboot_active_mb',
                    'Inactive'  : 'coldboot_inactive_mb',
                    }

class kernel_BootMessagesServer(test.test):
    version = 1


    def _read_dmesg(self, filename):
        """Put the contents of 'dmesg -r' into the given file.

        @param filename: The file to write 'dmesg -r' into.
        """
        f = open(filename, 'w')
        self._client.run('dmesg -r', stdout_tee=f)
        f.close()

        return utils.read_file(filename)

    def _reboot_machine(self):
        """Reboot the client machine.

        We'll wait until the client is down, then up again.
        """
        self._client.run('reboot')
        self._client.wait_down()
        self._client.wait_up()

    def _read_meminfo(self, filename):
        """Fetch /proc/meminfo from client and return lines in the file

        @param filename: The file to write 'cat /proc/meminfo' into.
        """

        f = open(filename, 'w')
        self._client.run('cat /proc/meminfo', stdout_tee=f)
        f.close()

        return utils.read_file(filename)

    def _parse_meminfo(self, meminfo, perf_vals):
        """ Parse the contents of each line of meminfo
            if the line matches one of the interesting keys
            save it into perf_vals in terms of megabytes

            @param filelines: list of lines in meminfo
            @param perf_vals: dictionary of performance metrics
        """

        for line in meminfo.splitlines():
            stuff = re.match('(.*):\s+(\d+)', line)
            stat  = stuff.group(1)
            if stat in _meminfo_fields:
                value  = int(stuff.group(2))/ 1024
                metric = _meminfo_fields[stat]
                perf_vals[metric] = value

    def _check_acpi_output(self, text, fwid):
        # This dictionary is the database of expected strings in dmesg output.
        # The keys are platform names, the values are two tuples, the first
        # element is the regex to filter the messages, the second element is a
        # set of strings to be found in the filtered dmesg set.
        message_db = {
            'Alex' : (r'(chromeos_acpi:|ChromeOS )', (
                    'chromeos_acpi: registering CHSW 0',
                    'chromeos_acpi: registering VBNV 0',
                    'chromeos_acpi: registering VBNV 1',
                    r'chromeos_acpi: truncating buffer from \d+ to \d+',
                    'chromeos_acpi: installed',
                    'ChromeOS firmware detected')),

            'Mario' : (r'(chromeos_acpi|ChromeOS )', (
                    'chromeos_acpi: falling back to default list of methods',
                    'chromeos_acpi: registering CHSW 0',
                    'chromeos_acpi: registering CHNV 0',
                    'chromeos_acpi: failed to retrieve MLST \(5\)',
                    'chromeos_acpi: installed',
                    'Legacy ChromeOS firmware detected'))
            }

        if fwid not in message_db:
            msg = 'Unnown platform %s, acpi dmesg set not defined.' % fwid
            logging.error(msg)
            raise error.TestFail(msg)

        rv = utils.verify_mesg_set(text,
                                   message_db[fwid][0],
                                   message_db[fwid][1])
        if rv:
            logging.error('ACPI mismatch\n%s:' % rv)
            raise error.TestFail('ACPI dmesg mismatch')

    def run_once(self, host=None):
        """Run the test.

        @param host: The client machine to connect to; should be a Host object.
        """
        assert host is not None, "The host must be specified."

        self._client = host

        # get the firmware identifier from Crossystem
        cs = utils.Crossystem(self._client)
        cs.init()
        fwid = cs.fwid().split('.')[0]

        dmesg_filename = os.path.join(self.resultsdir, 'dmesg')
        meminfo_filename = os.path.join(self.resultsdir, 'meminfo')
        perf_vals = {}

        self._reboot_machine()
        meminfo = self._read_meminfo(meminfo_filename)
        self._parse_meminfo(meminfo, perf_vals)
        dmesg = self._read_dmesg(dmesg_filename)

        if fwid not in _WHITELIST_TARGETS:
            msg = 'Unnown platform %s, whitelist dmesg set not defined.' % fwid
            logging.error(msg)
            raise error.TestFail(msg)

        unexpected = utils.check_raw_dmesg(
            dmesg, _KERN_WARNING, _WHITELIST_COMMON + _WHITELIST_TARGETS[fwid])

        if unexpected:
            f = open(os.path.join(self.resultsdir, 'dmesg.err'), 'w')
            for line in unexpected:
                logging.error('UNEXPECTED DMESG: %s' % line)
                f.write('%s\n' % line)
            f.close()
            raise error.TestFail("Unexpected dmesg warnings and/or errors.")

        self.write_perf_keyval(perf_vals)

        self._check_acpi_output(dmesg, fwid)