blob: 18f336fd565a9a047f3d7b0456cc7826ef2754fd [file] [log] [blame]
#!/usr/bin/python
# Copyright (c) 2010 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.
"""A script to manipulate ChromeOS CMOS reboot Field.
A few bits in a byte in CMOS (called RDB, short for 'Reboot Data Byte'
hereafter) are dedicated to information exchange between Linux and BIOS.
The CMOS contents are available through /dev/nvrom. The location of RDB is
reported by BIOS through ACPI. The few bits in RDB operated on by this script
are defined in the all_mode_fields dictionary below along with their
functions.
When invoked without parameters this script prints values of the fields. When
invoked with any of the bit field names as parameter(s), the script sets the
bit(s) as required.
Additional parameters allow to specify alternative ACPI and NVRAM files for
testing.
"""
__author__ = 'The Chromium OS Authors'
import optparse
import sys
class RebootModeError(Exception):
pass
# global variables
parser = optparse.OptionParser()
acpi_file = '/sys/devices/platform/chromeos_acpi/CHNV'
nvram_file = '/dev/nvram'
# Offset of RDB in NVRAM
rdb_offset = 0
# NVRAM contents read on startup
rdb_value = ''
# All bitfields in RDB this script provides access to. Field names prepended
# by `--' become this script's command line options
all_mode_fields = {
'recovery' : 0x80,
'debug_reset' : 0x40,
'try_firmware_b': 0x20
}
# A dictionary of fields to be updated as requested by the command line
# parameters
fields_to_set = {}
def OptionHandler(option, opt_str, value, p):
"""Process bit field name command line parameter.
Verifies that the value is in range (0 or 1) and adds the appropriate
element to fields_to_set dictionary. Should the same field specified in the
command line more than once, only the last value will be used.
Raises:
RebootModeError in case the parameter value is out of range.
"""
global fields_to_set
key = opt_str[2:]
if value < 0 or value > 1:
raise RebootModeError('--%s should be either 0 or 1' % key)
fields_to_set[key] = value
def PrepareOptions():
global parser
for field in all_mode_fields:
parser.add_option('--' + field, action='callback', type='int',
callback=OptionHandler)
parser.add_option('--acpi_file', dest='acpi_file')
parser.add_option('--nvram_file', dest='nvram_file')
def ParseOptions():
global acpi_file
global nvram_file
(opts, args) = parser.parse_args()
if opts.acpi_file is not None:
acpi_file = opts.acpi_file
if opts.nvram_file is not None:
nvram_file = opts.nvram_file
def GetRDBOffset():
global rdb_offset
try:
f = open(acpi_file, 'r')
rdb_offset = int(f.read())
f.close()
except IOError, e:
raise RebootModeError('Trying to read %s got this: %s' % (acpi_file, e))
except ValueError:
raise RebootModeError('%s contents are corrupted' % acpi_file)
def ReadNvram():
global rdb_value
try:
f = open(nvram_file, 'rb')
f.seek(rdb_offset)
rdb_value = ord(f.read(1)[0])
f.close()
except IOError, e:
if e[0] == 2:
raise RebootModeError(
'%s does not exist. Is nvram module installed?' % nvram_file)
if e[0] == 13:
raise RebootModeError('Access to %s denied. Are you root?' % nvram_file)
raise RebootModeError(e[1])
except IndexError, e:
raise RebootModeError('Failed reading mode byte from %s' % nvram_file)
def PrintCurrentMode():
print 'Current reboot mode settings:'
for (field, mask) in all_mode_fields.iteritems():
print '%-15s: %d' % (field, int(not not (rdb_value & mask)))
def SetNewMode():
new_mode = 0
updated_bits_mask = 0
for (opt, value) in fields_to_set.iteritems():
mask = all_mode_fields[opt]
if value:
new_mode |= mask
updated_bits_mask |= mask
if (rdb_value & updated_bits_mask) == new_mode:
print 'No update required'
return
f = open(nvram_file, 'rb+')
f.seek(rdb_offset)
new_mode |= (rdb_value & ~updated_bits_mask)
f.write('%c' % new_mode)
f.close()
def DoRebootMode():
PrepareOptions()
ParseOptions()
GetRDBOffset()
ReadNvram()
if fields_to_set:
SetNewMode()
else:
PrintCurrentMode()
if __name__ == '__main__':
try:
DoRebootMode()
except RebootModeError, e:
print >> sys.stderr, '%s: %s' % (sys.argv[0].split('/')[-1], e)
sys.exit(1)
sys.exit(0)