| OLD | NEW | 
|    1 #!/usr/bin/python |    1 #!/usr/bin/python | 
|    2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |    2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 
|    3 # Use of this source code is governed by a BSD-style license that can be |    3 # Use of this source code is governed by a BSD-style license that can be | 
|    4 # found in the LICENSE file. |    4 # found in the LICENSE file. | 
|    5  |    5  | 
|    6 '''Test utility for verifying ChromeOS firmware.''' |    6 '''Test utility for verifying ChromeOS firmware.''' | 
|    7  |    7  | 
|    8 import datetime |    8 import datetime | 
|    9 import functools |    9 import functools | 
|   10 import getopt |   10 import getopt | 
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   90 STEP_FILE = 'fw_test_step'  # The next test step number. |   90 STEP_FILE = 'fw_test_step'  # The next test step number. | 
|   91 FW_BACKUP_FILE = 'flashrom.bak'  # Preserved original flashrom contents. |   91 FW_BACKUP_FILE = 'flashrom.bak'  # Preserved original flashrom contents. | 
|   92 FW_COPY_FILE = 'flashrom.new'  # A copy of the flashrom contents being tested. |   92 FW_COPY_FILE = 'flashrom.new'  # A copy of the flashrom contents being tested. | 
|   93 FWID_BACKUP_FILE = 'fwid.bak'  # FWID reported by the original firmware. |   93 FWID_BACKUP_FILE = 'fwid.bak'  # FWID reported by the original firmware. | 
|   94 FWID_NEW_FILE = 'fwid.new'  # FWID reported by the firmware being tested. |   94 FWID_NEW_FILE = 'fwid.new'  # FWID reported by the firmware being tested. | 
|   95  |   95  | 
|   96 BASE_STORAGE_DEVICE = '/dev/sda' |   96 BASE_STORAGE_DEVICE = '/dev/sda' | 
|   97  |   97  | 
|   98 # The list of shell executables necessary for this program to work. |   98 # The list of shell executables necessary for this program to work. | 
|   99 REQUIRED_PROGRAMS = ''' |   99 REQUIRED_PROGRAMS = ''' | 
|  100 cgpt blkid flashrom reboot_mode readlink rootdev vbutil_firmware vbutil_kernel |  100 cgpt crossystem blkid flashrom readlink rootdev vbutil_firmware vbutil_kernel | 
|  101 mosys |  101 mosys | 
|  102 ''' |  102 ''' | 
|  103  |  103  | 
|  104  |  104  | 
|  105 FLASHROM_HANDLER = flashrom_handler.FlashromHandler() |  105 FLASHROM_HANDLER = flashrom_handler.FlashromHandler() | 
|  106 CHROS_IF = chromeos_interface.ChromeOSInterface(__name__ != '__main__') |  106 CHROS_IF = chromeos_interface.ChromeOSInterface(__name__ != '__main__') | 
|  107 cgpt_st = cgpt_state.CgptState('COMPLETE', CHROS_IF, BASE_STORAGE_DEVICE) |  107 cgpt_st = cgpt_state.CgptState('COMPLETE', CHROS_IF, BASE_STORAGE_DEVICE) | 
|  108  |  108  | 
|  109 def allow_multiple_section_input(image_operator): |  109 def allow_multiple_section_input(image_operator): | 
|  110     @functools.wraps(image_operator) |  110     @functools.wraps(image_operator) | 
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  168         self.window = None |  168         self.window = None | 
|  169         self.tpm_handler = None |  169         self.tpm_handler = None | 
|  170  |  170  | 
|  171     def _verify_fw_id(self, compare_to_file): |  171     def _verify_fw_id(self, compare_to_file): | 
|  172         '''Verify if the current firmware ID matches the contents a file. |  172         '''Verify if the current firmware ID matches the contents a file. | 
|  173  |  173  | 
|  174         compare_to_file - a string, name of the file in the state directory. |  174         compare_to_file - a string, name of the file in the state directory. | 
|  175         ''' |  175         ''' | 
|  176         old_fwid = open( |  176         old_fwid = open( | 
|  177             self.chros_if.state_dir_file(compare_to_file), 'r').read() |  177             self.chros_if.state_dir_file(compare_to_file), 'r').read() | 
|  178         now_fwid = open(self.chros_if.acpi_file('FWID'), 'r').read() |  178         now_fwid = self.chros_if.cs.fwid | 
|  179         return old_fwid == now_fwid |  179         return old_fwid == now_fwid | 
|  180  |  180  | 
|  181     def _get_step(self): |  181     def _get_step(self): | 
|  182         '''Set the current value of SAFT step number.''' |  182         '''Set the current value of SAFT step number.''' | 
|  183         step_file = self.chros_if.state_dir_file(STEP_FILE) |  183         step_file = self.chros_if.state_dir_file(STEP_FILE) | 
|  184         step = open(step_file, 'r').read().strip() |  184         step = open(step_file, 'r').read().strip() | 
|  185         return int(step) |  185         return int(step) | 
|  186  |  186  | 
|  187     def _set_step(self, step): |  187     def _set_step(self, step): | 
|  188         '''Set the SAFT step number to control the next test pass.''' |  188         '''Set the SAFT step number to control the next test pass.''' | 
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  245  |  245  | 
|  246         os.rmdir(tmp_dir) |  246         os.rmdir(tmp_dir) | 
|  247  |  247  | 
|  248     def _check_runtime_env(self): |  248     def _check_runtime_env(self): | 
|  249         '''Ensure that the script is running in proper environment. |  249         '''Ensure that the script is running in proper environment. | 
|  250  |  250  | 
|  251       This involves checking that the script is running off a removable |  251       This involves checking that the script is running off a removable | 
|  252       device, configuring proper file names for logging, etc. |  252       device, configuring proper file names for logging, etc. | 
|  253       ''' |  253       ''' | 
|  254         line = self.chros_if.run_shell_command_get_output( |  254         line = self.chros_if.run_shell_command_get_output( | 
|  255             'df %s' % self.mydir)[-1] |  255             'df %s' % self.mydir)[1] | 
|  256  |  256  | 
|  257         self.base_partition = line.split()[0] |  257         self.base_partition = line.split()[0] | 
|  258         if self.base_partition == '/dev/root': |  258         if self.base_partition == '/dev/root': | 
|  259             self.base_partition = self.chros_if.get_root_dev() |  259             self.base_partition = self.chros_if.get_root_dev() | 
|  260  |  260  | 
|  261         if not self.chros_if.is_removable_device(self.base_partition): |  261         if not self.chros_if.is_removable_device(self.base_partition): | 
|  262             raise FwError( |  262             raise FwError( | 
|  263                 'This test must run off a removable device, not %s' |  263                 'This test must run off a removable device, not %s' | 
|  264                 % self.base_partition) |  264                 % self.base_partition) | 
|  265  |  265  | 
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  336                 if self.kern_handler: |  336                 if self.kern_handler: | 
|  337                     vers_a = self.kern_handler.get_version('a') |  337                     vers_a = self.kern_handler.get_version('a') | 
|  338                     vers_b = self.kern_handler.get_version('b') |  338                     vers_b = self.kern_handler.get_version('b') | 
|  339                     if not self.tpm_handler.kernel_version_good(vers_a, vers_b): |  339                     if not self.tpm_handler.kernel_version_good(vers_a, vers_b): | 
|  340                         raise FwError('TPM kernel version mismatch (%d %d %s)' %
      ( |  340                         raise FwError('TPM kernel version mismatch (%d %d %s)' %
      ( | 
|  341                                 vers_a, vers_b, self.base_partition)) |  341                                 vers_a, vers_b, self.base_partition)) | 
|  342  |  342  | 
|  343     def set_try_fw_b(self): |  343     def set_try_fw_b(self): | 
|  344         '''Request running firmware B on the next restart.''' |  344         '''Request running firmware B on the next restart.''' | 
|  345         self.chros_if.log('Requesting restart with FW B') |  345         self.chros_if.log('Requesting restart with FW B') | 
|  346         self.chros_if.run_shell_command('reboot_mode --try_firmware_b=1') |  346         self.chros_if.cs.fwb_tries = 1 | 
|  347  |  347  | 
|  348     def request_recovery_boot(self): |  348     def request_recovery_boot(self): | 
|  349         '''Request running in recovery mode on the restart.''' |  349         '''Request running in recovery mode on the restart.''' | 
|  350         self.chros_if.log('Requesting restart in recovery mode') |  350         self.chros_if.log('Requesting restart in recovery mode') | 
|  351         self.chros_if.run_shell_command('reboot_mode --recovery=1') |  351         self.chros_if.cs.request_recovery() | 
 |  352  | 
|  352  |  353  | 
|  353     @allow_multiple_section_input |  354     @allow_multiple_section_input | 
|  354     def restore_firmware(self, section): |  355     def restore_firmware(self, section): | 
|  355         '''Restore the requested firmware section (previously corrupted).''' |  356         '''Restore the requested firmware section (previously corrupted).''' | 
|  356         self.chros_if.log('Restoring firmware %s' % section) |  357         self.chros_if.log('Restoring firmware %s' % section) | 
|  357         FLASHROM_HANDLER.restore_firmware(section) |  358         FLASHROM_HANDLER.restore_firmware(section) | 
|  358  |  359  | 
|  359     @allow_multiple_section_input |  360     @allow_multiple_section_input | 
|  360     def corrupt_firmware(self, section): |  361     def corrupt_firmware(self, section): | 
|  361         '''Corrupt the requested firmware section.''' |  362         '''Corrupt the requested firmware section.''' | 
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  522                 datetime.datetime.strftime( |  523                 datetime.datetime.strftime( | 
|  523                     datetime.datetime.now(), '%b %d %Y'))) |  524                     datetime.datetime.now(), '%b %d %Y'))) | 
|  524         chros_if.log('Original boot state %s' % chros_if.boot_state_vector()) |  525         chros_if.log('Original boot state %s' % chros_if.boot_state_vector()) | 
|  525         self.chros_if = chros_if |  526         self.chros_if = chros_if | 
|  526         fw_image = opt_dictionary['image_file'] |  527         fw_image = opt_dictionary['image_file'] | 
|  527         self.new_fw_image() |  528         self.new_fw_image() | 
|  528         FLASHROM_HANDLER.dump_whole( |  529         FLASHROM_HANDLER.dump_whole( | 
|  529             self.chros_if.state_dir_file(FW_BACKUP_FILE)) |  530             self.chros_if.state_dir_file(FW_BACKUP_FILE)) | 
|  530         self.new_fw_image(fw_image) |  531         self.new_fw_image(fw_image) | 
|  531         self._handle_saft_script(True) |  532         self._handle_saft_script(True) | 
|  532         shutil.copyfile(self.chros_if.acpi_file('FWID'), |  533         open(self.chros_if.state_dir_file(FWID_BACKUP_FILE), 'w' | 
|  533                         self.chros_if.state_dir_file(FWID_BACKUP_FILE)) |  534              ).write(self.chros_if.cs.fwid) | 
|  534         shutil.copyfile(fw_image, self.chros_if.state_dir_file(FW_COPY_FILE)) |  535         shutil.copyfile(fw_image, self.chros_if.state_dir_file(FW_COPY_FILE)) | 
|  535  |  536  | 
|  536         self._set_step(0) |  537         self._set_step(0) | 
|  537         cgpt_st.set_step(0) |  538         cgpt_st.set_step(0) | 
|  538  |  539  | 
|  539     def next_step(self): |  540     def next_step(self): | 
|  540         '''Function to execute a single SAFT step. |  541         '''Function to execute a single SAFT step. | 
|  541  |  542  | 
|  542       This function is running after each reboot. It determines the current |  543       This function is running after each reboot. It determines the current | 
|  543       step the SAFT is on, executes the appropriate action, increments the |  544       step the SAFT is on, executes the appropriate action, increments the | 
|  544       step value and then restats the machine. |  545       step value and then restats the machine. | 
|  545       ''' |  546       ''' | 
|  546  |  547  | 
|  547         this_step = self._get_step() |  548         this_step = self._get_step() | 
|  548  |  549  | 
|  549         # Import when needed, because otherwise running test generates a |  550         # Import when needed, because otherwise running test generates a | 
|  550         # warning exception about the unavailable display. |  551         # warning exception about the unavailable display. | 
|  551         window = __import__('window') |  552         window = __import__('window') | 
|  552         self.window = window.GraphThread() |  553         self.window = window.GraphThread() | 
|  553  |  554  | 
|  554         if this_step == 0: |  555         if this_step == 0: | 
|  555             shutil.copyfile(self.chros_if.acpi_file('FWID'), |  556             open(self.chros_if.state_dir_file(FWID_NEW_FILE), 'w' | 
|  556                             self.chros_if.state_dir_file(FWID_NEW_FILE)) |  557                  ).write(self.chros_if.cs.fwid) | 
|  557  |  558  | 
|  558             if self._verify_fw_id(FWID_BACKUP_FILE): |  559             if self._verify_fw_id(FWID_BACKUP_FILE): | 
|  559           # we expected FWID to change, but it did not - have the firmware |  560           # we expected FWID to change, but it did not - have the firmware | 
|  560           # been even replaced? |  561           # been even replaced? | 
|  561                 self.chros_if.log('New firmware - old FWID') |  562                 self.chros_if.log('New firmware - old FWID') | 
|  562                 self.finish_saft(False) |  563                 self.finish_saft(False) | 
|  563         test_state_tuple = self.test_state_sequence[this_step] |  564         test_state_tuple = self.test_state_sequence[this_step] | 
|  564         expected_vector = test_state_tuple[0] |  565         expected_vector = test_state_tuple[0] | 
|  565         action = test_state_tuple[1] |  566         action = test_state_tuple[1] | 
|  566  |  567  | 
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  634             # Have chros_if.shutdown move the log into the '/var' directory to |  635             # Have chros_if.shutdown move the log into the '/var' directory to | 
|  635             # make it easier to see SAFT results. |  636             # make it easier to see SAFT results. | 
|  636             self.chros_if.shut_down(os.path.join('/var', LOG_FILE)) |  637             self.chros_if.shut_down(os.path.join('/var', LOG_FILE)) | 
|  637  |  638  | 
|  638         self.window.stop() |  639         self.window.stop() | 
|  639         sys.exit(0) |  640         sys.exit(0) | 
|  640  |  641  | 
|  641 # Firmware self test instance controlling this module. |  642 # Firmware self test instance controlling this module. | 
|  642 FST = FirmwareTest() |  643 FST = FirmwareTest() | 
|  643  |  644  | 
|  644 # This is a tuple of tuples controlling the SAFT state machine. The states |  645 # This is a tuple of tuples controlling the SAFT state machine. The states are | 
|  645 # are expected to be passed strictly in order. The states are identified |  646 # expected to be passed strictly in order. The states used to be identified by | 
|  646 # by the contents of BINF.[012] files in the sys fs ACPI directory. The |  647 # the contents of BINF.[012] files in the sys fs ACPI directory. Now they are | 
|  647 # BINF files store information about the reason for reboot, what |  648 # derived from the crossystem output to match previously reported states. | 
|  648 # firmware/kernel partitions were used, etc. |  | 
|  649 # |  649 # | 
|  650 # The first element of each component tuple is the expected state of the |  650 # The first element of each component tuple is the expected state of the | 
|  651 # machine (a ':' concatenation of the BINF files' contents). |  651 # machine. | 
|  652 # |  652 # | 
|  653 # The second element of the component tuples is the action to take to |  653 # The second element of the component tuples is the action to take to | 
|  654 # advance the test. The action is a function to call. The last line has |  654 # advance the test. The action is a function to call. The last line has | 
|  655 # action set to None, which indicates to the state machine that the test |  655 # action set to None, which indicates to the state machine that the test | 
|  656 # is over. |  656 # is over. | 
|  657 # |  657 # | 
|  658 # The third component, if present, is the parameter to pass to the action |  658 # The third component, if present, is the parameter to pass to the action | 
|  659 # function. |  659 # function. | 
|  660  |  660  | 
|  661 TEST_STATE_SEQUENCE = ( |  661 TEST_STATE_SEQUENCE = ( | 
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  768     if 'next_step' in opt_dictionary: |  768     if 'next_step' in opt_dictionary: | 
|  769         if len(opt_dictionary) != 1: |  769         if len(opt_dictionary) != 1: | 
|  770             usage('--next_step (when specified) must be the only parameter', 1) |  770             usage('--next_step (when specified) must be the only parameter', 1) | 
|  771         try: |  771         try: | 
|  772             FST.next_step() |  772             FST.next_step() | 
|  773         except SystemExit: |  773         except SystemExit: | 
|  774             pass  # No real exception, this is just an exit (for whatever |  774             pass  # No real exception, this is just an exit (for whatever | 
|  775                   # reason), gtk window already closed. |  775                   # reason), gtk window already closed. | 
|  776         except: |  776         except: | 
|  777             # Whatever error that might be, gtk window must be shut. |  777             # Whatever error that might be, gtk window must be shut. | 
|  778             FST.window.stop() |  778             if FST.window: | 
 |  779                 FST.window.stop() | 
|  779  |  780  | 
|  780             # Make sure exception information is saved in the log. |  781             # Make sure exception information is saved in the log. | 
|  781             exc_type, exc_info, exc_trace = sys.exc_info() |  782             exc_type, exc_info, exc_trace = sys.exc_info() | 
|  782             print 'exception type:', str(exc_type) |  783             print 'exception type:', str(exc_type) | 
|  783             print 'exception info:', str(exc_info) |  784             print 'exception info:', str(exc_info) | 
|  784             traceback.print_tb(exc_trace) |  785             traceback.print_tb(exc_trace) | 
|  785         sys.exit(0) |  786         sys.exit(0) | 
|  786  |  787  | 
|  787     # check if all executables are available |  788     # check if all executables are available | 
|  788     missing_execs = [] |  789     missing_execs = [] | 
| (...skipping 30 matching lines...) Expand all  Loading... | 
|  819         main(sys.argv) |  820         main(sys.argv) | 
|  820     except (getopt.GetoptError, ImportError): |  821     except (getopt.GetoptError, ImportError): | 
|  821         usage(sys.exc_info()[1], 1) |  822         usage(sys.exc_info()[1], 1) | 
|  822     except (FwError, flashrom_handler.FlashromHandlerError): |  823     except (FwError, flashrom_handler.FlashromHandlerError): | 
|  823         MSG = 'Error: %s' % str(sys.exc_info()[1]) |  824         MSG = 'Error: %s' % str(sys.exc_info()[1]) | 
|  824         print MSG |  825         print MSG | 
|  825         CHROS_IF.log(MSG) |  826         CHROS_IF.log(MSG) | 
|  826         sys.exit(1) |  827         sys.exit(1) | 
|  827  |  828  | 
|  828     sys.exit(0) |  829     sys.exit(0) | 
| OLD | NEW |