Chromium Code Reviews| 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 '''A module to provide interface to ChromeOS services.''' | 6 '''A module to provide interface to ChromeOS services.''' |
| 7 | 7 |
| 8 import datetime | 8 import datetime |
| 9 import os | 9 import os |
| 10 import re | 10 import re |
| 11 import shutil | 11 import shutil |
| 12 import struct | 12 import struct |
| 13 import subprocess | 13 import subprocess |
| 14 import tempfile | 14 import tempfile |
| 15 import time | 15 import time |
| 16 | 16 |
| 17 class ChromeOSInterfaceError(Exception): | 17 class ChromeOSInterfaceError(Exception): |
| 18 '''ChromeOS interface specific exception.''' | 18 '''ChromeOS interface specific exception.''' |
| 19 pass | 19 pass |
| 20 | 20 |
| 21 class Crossystem(object): | 21 class Crossystem(object): |
| 22 '''A wrapper for the crossystem utility.''' | 22 '''A wrapper for the crossystem utility.''' |
| 23 | 23 |
| 24 # Code dedicated for user triggering recovery mode through crossystem. | |
| 25 USER_RECOVERY_REQUEST_CODE = '193' | |
| 26 | |
| 27 ''' | |
| 28 The first three legacy boot vector digits are the boot vector base (the | |
| 29 entire vector consists of 5 digits). They used to be reported by the BIOS | |
| 30 through ACPI, but that scheme has been superseded by the 'crossystem' | |
| 31 interface. | |
| 32 | |
| 33 The digits of the boot vector base have the following significance | |
| 34 | |
| 35 - first digit - | |
| 36 1 - normal boot | |
| 37 2 - developer mode boot | |
| 38 3 - recovery initialed by pressing the recovery button | |
| 39 4 - recovery from developer mode warning screen | |
| 40 5 - recovery caused by both firmware images being invalid | |
| 41 6 - recovery caused by both kernel images being invalid | |
| 42 8 - recovery initiated by user | |
| 43 | |
| 44 - second digit - | |
| 45 0 - recovery firmware | |
| 46 1 - rewritable firmware A | |
| 47 2 - rewritable firmware B | |
| 48 | |
| 49 - third digit - | |
| 50 0 - Read only (recovery) EC firmware | |
| 51 1 - rewritable EC firmware | |
| 52 | |
| 53 | |
| 54 Below is a list of dictionaries to map current system state as reported by | |
| 55 'crossystem' into the 'legacy' boot vector digits. | |
| 56 | |
| 57 The three elements of the list represent the three digits of the boot | |
| 58 vector. Each list element is a dictionary where the key is the legacy boot | |
| 59 vector value in the appropriate position, and the value is in turn a | |
| 60 dictionary of name-value pairs. | |
| 61 | |
| 62 If all name-value pairs of a dictionary element match those reported by | |
| 63 crossystem, the legacy representation number is considered the appropriate | |
| 64 vector digit. | |
| 65 | |
| 66 Note that on some platforms (namely, Mario) same parameters returned by | |
| 67 crossystem are set to a wrong value. The class init() routine adjust the | |
| 68 list to support those platforms. | |
| 69 ''' | |
| 70 | |
| 71 VECTOR_MAPS = [ | |
| 72 { # first vector position | |
| 73 '1': { | |
| 74 'devsw_boot': '0', | |
| 75 'mainfw_type': 'normal', | |
| 76 'recoverysw_boot': '0', | |
| 77 }, | |
| 78 '5': { | |
| 79 'devsw_boot': '0', | |
| 80 'recoverysw_boot': '0', | |
| 81 'recovery_reason' : '3', | |
| 82 'mainfw_type': 'recovery', | |
| 83 }, | |
| 84 '6': { | |
| 85 'devsw_boot': '0', | |
| 86 'recoverysw_boot': '0', | |
| 87 'recovery_reason' : '66', | |
| 88 'mainfw_type': 'recovery', | |
| 89 }, | |
| 90 '8': { | |
| 91 'devsw_boot': '0', | |
| 92 'recoverysw_boot': '0', | |
| 93 'recovery_reason' : USER_RECOVERY_REQUEST_CODE, | |
| 94 'mainfw_type': 'recovery', | |
| 95 }, | |
| 96 }, | |
| 97 { # second vector position | |
| 98 '0': {'mainfw_type': 'recovery',}, | |
| 99 '1': { | |
| 100 'mainfw_type': 'normal', | |
| 101 'mainfw_act': 'A' | |
| 102 }, | |
| 103 '2': { | |
| 104 'mainfw_type': 'normal', | |
| 105 'mainfw_act': 'B' | |
| 106 }, | |
| 107 }, | |
| 108 { # third vector position | |
| 109 '0': {'ecfw_act': 'RO',}, | |
| 110 '1': {'ecfw_act': 'RW',}, | |
| 111 }, | |
| 112 ] | |
| 113 | |
| 24 def init(self, cros_if): | 114 def init(self, cros_if): |
| 115 '''Init the instance. If running on Mario - adjust the map.''' | |
| 116 | |
| 25 self.cros_if = cros_if | 117 self.cros_if = cros_if |
| 26 | 118 |
| 119 # Hack Alert!!! Adjust vector map to work on Mario | |
| 120 fwid = self.__getattr__('fwid').lower() | |
| 121 if not 'mario' in fwid: | |
| 122 return | |
| 123 # Mario firmware is broken and always reports recovery switch as set | |
| 124 # at boot time when booting up in recovery mode. This is why we | |
| 125 # exclude recoverysw_boot from the map when running on mario. | |
| 126 for state in self.VECTOR_MAPS[0].itervalues(): | |
| 127 if state['mainfw_type'] != 'recovery': | |
| 128 continue | |
| 129 if 'recoverysw_boot' in state: | |
| 130 del(state['recoverysw_boot']) | |
| 131 | |
| 27 def __getattr__(self, name): | 132 def __getattr__(self, name): |
| 28 ''' | 133 ''' |
| 29 Retrieve a crosssystem attribute. | 134 Retrieve a crosssystem attribute. |
| 30 | 135 |
| 31 Attempt to access crossystemobject.name will invoke `crossystem name' | 136 Attempt to access crossystemobject.name will invoke `crossystem name' |
| 32 and return the stdout as the value. | 137 and return the stdout as the value. |
| 33 ''' | 138 ''' |
| 34 return self.cros_if.run_shell_command_get_output( | 139 return self.cros_if.run_shell_command_get_output( |
| 35 'crossystem %s' % name)[0] | 140 'crossystem %s' % name)[0] |
| 36 | 141 |
| 37 def __setattr__(self, name, value): | 142 def __setattr__(self, name, value): |
| 38 if name in ('cros_if',): | 143 if name in ('cros_if',): |
| 39 self.__dict__[name] = value | 144 self.__dict__[name] = value |
| 40 else: | 145 else: |
| 41 self.cros_if.run_shell_command('crossystem "%s=%s"' % (name, value)) | 146 self.cros_if.run_shell_command('crossystem "%s=%s"' % (name, value)) |
| 42 | 147 |
| 148 def request_recovery(self): | |
| 149 '''Request recovery mode next time the target reboots.''' | |
| 150 | |
| 151 self.__setattr__('recovery_request', self.USER_RECOVERY_REQUEST_CODE) | |
| 43 | 152 |
| 44 def get_boot_vector_base(self): | 153 def get_boot_vector_base(self): |
| 45 ''' | 154 '''Convert system state into a legacy boot vector base. |
| 46 Convert system state into a legacy boot vector base. | |
| 47 | 155 |
| 48 The first three legacy boot vector digits are the boot vector base | 156 The function looks up the VECTOR_MAPS list above to find the digits |
| 49 (the entire vector consists of 5 digits). They used to be reported by | 157 matching the current crossystem output, and returns a list of three |
| 50 the BIOS through ACPI, but that scheme has been superseded by the | 158 digits in symbolic representation, which become the base of the 5 |
| 51 'crossystem' interface. | 159 digit boot state vecotr. |
| 52 | 160 |
| 53 The digits of the boot vector base have the following significance | 161 Should it be impossible to interpret the state, the function returns |
| 54 | |
| 55 - first digit - | |
| 56 1 - normal boot | |
| 57 2 - developer mode boot | |
| 58 3 - recovery initialed by pressing the recovery button | |
| 59 4 - recovery from developer mode warning screen | |
| 60 5 - recovery caused by both firmware images being invalid | |
| 61 6 - recovery caused by both kernel images being invalid | |
| 62 | |
| 63 - second digit - | |
| 64 0 - recovery firmware | |
| 65 1 - rewritable firmware A | |
| 66 2 - rewritable firmware B | |
| 67 | |
| 68 - third digit - | |
| 69 0 - Read only (recovery) EC firmware | |
| 70 1 - rewritable EC firmware | |
| 71 | |
| 72 | |
| 73 This function uses a three tuple of dictionaries to map current system | |
| 74 state as reported by 'crossystem' into the 'legacy' boot vector | |
| 75 digits. | |
| 76 | |
| 77 Each tuple element is a dictionary, where the key is the 'legacy' | |
| 78 representation of the state, and the value is a yet another dictionary | |
| 79 of name-value pairs. | |
| 80 | |
| 81 If all name-value pairs match those in the crossystem output, the | |
| 82 legacy representation number is returned as the appropriate vector | |
| 83 number. | |
| 84 | |
| 85 The function returns a list of three digits in symbolic representation. | |
| 86 | |
| 87 Should it be impossible to interpret the state, the function returns a | |
| 88 partially built list, which is an indication of a problem for the | 162 partially built list, which is an indication of a problem for the |
|
Randall Spangler
2011/04/19 19:40:32
'a partially built list'
vb
2011/04/19 21:15:22
Done.
| |
| 89 caller (list shorter than 3 elements). | 163 caller (list shorter than 3 elements). |
| 90 ''' | 164 ''' |
| 91 | 165 |
| 92 vector_maps = ( | |
| 93 { # first vector position | |
| 94 '1': { | |
| 95 'devsw_boot': '0', | |
| 96 'recoverysw_boot': '0', | |
| 97 'recovery_reason' : '0', | |
| 98 'tried_fwb' : '0', | |
| 99 }, | |
| 100 }, | |
| 101 { # second vector position | |
| 102 '0': {'mainfw_type': 'recovery',}, | |
| 103 '1': { | |
| 104 'mainfw_type': 'normal', | |
| 105 'mainfw_act': 'A' | |
| 106 }, | |
| 107 '2': { | |
| 108 'mainfw_type': 'normal', | |
| 109 'mainfw_act': 'B' | |
| 110 }, | |
| 111 }, | |
| 112 { # third vector position | |
| 113 '0': {'ecfw_act': 'RO',}, | |
| 114 '1': {'ecfw_act': 'RW',}, | |
| 115 }, | |
| 116 ) | |
| 117 | |
| 118 boot_vector = [] | 166 boot_vector = [] |
| 119 | 167 |
| 120 for vector_map in vector_maps: | 168 for vector_map in self.VECTOR_MAPS: |
| 121 for (digit, values) in vector_map.iteritems(): | 169 for (digit, values) in vector_map.iteritems(): |
| 122 for (name, value) in values.iteritems(): | 170 for (name, value) in values.iteritems(): |
| 123 if self.__getattr__(name) != value: | 171 if self.__getattr__(name) != value: |
| 124 break | 172 break |
| 125 else: | 173 else: |
| 126 boot_vector.append(digit) | 174 boot_vector.append(digit) |
| 127 break | 175 break |
| 128 | 176 |
| 129 return boot_vector | 177 return boot_vector |
| 130 | 178 |
| 131 def dump(self): | 179 def dump(self): |
| 132 '''Dump all values as multiline text.''' | 180 '''Dump all crossystem values as multiline text.''' |
| 181 | |
| 133 return '\n'.join(self.cros_if.run_shell_command_get_output( | 182 return '\n'.join(self.cros_if.run_shell_command_get_output( |
| 134 'crossystem')) | 183 'crossystem')) |
| 135 | 184 |
| 136 | 185 |
| 137 class ChromeOSInterface(object): | 186 class ChromeOSInterface(object): |
| 138 '''An object to encapsulate OS services functions.''' | 187 '''An object to encapsulate OS services functions.''' |
| 139 | 188 |
| 140 def __init__(self, silent): | 189 def __init__(self, silent): |
| 141 '''Object construction time initialization. | 190 '''Object construction time initialization. |
| 142 | 191 |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 376 def read_partition(self, partition, size): | 425 def read_partition(self, partition, size): |
| 377 '''Read the requested partition, up to size bytes.''' | 426 '''Read the requested partition, up to size bytes.''' |
| 378 tmp_file = self.state_dir_file('part.tmp') | 427 tmp_file = self.state_dir_file('part.tmp') |
| 379 self.run_shell_command('dd if=%s of=%s bs=1 count=%d' % ( | 428 self.run_shell_command('dd if=%s of=%s bs=1 count=%d' % ( |
| 380 partition, tmp_file, size)) | 429 partition, tmp_file, size)) |
| 381 fileh = open(tmp_file, 'r') | 430 fileh = open(tmp_file, 'r') |
| 382 data = fileh.read() | 431 data = fileh.read() |
| 383 fileh.close() | 432 fileh.close() |
| 384 os.remove(tmp_file) | 433 os.remove(tmp_file) |
| 385 return data | 434 return data |
| OLD | NEW |