Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(271)

Unified Diff: reboot_mode.cc

Issue 2656004: add c++ version of the firmware utilities (Closed) Base URL: ssh://gitrw.chromium.org/firmware-utils.git
Patch Set: removed python scripts and add comments for range names in gpio Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « gpio_setup.py ('k') | reboot_mode.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: reboot_mode.cc
diff --git a/reboot_mode.cc b/reboot_mode.cc
new file mode 100644
index 0000000000000000000000000000000000000000..57a5bc8bce049b34a544261af19bd3465b83faf3
--- /dev/null
+++ b/reboot_mode.cc
@@ -0,0 +1,298 @@
+// 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.
+
+// NOTE: this file is translated from reboot_mode.py
+//
+// 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.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <stdint.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <getopt.h>
+
+#include <string>
+#include <algorithm>
+#include <vector>
+#include <map>
+
+#define DEFAULT_ACPI_FILE "/sys/devices/platform/chromeos_acpi/CHNV"
+#define DEFAULT_NVRAM_FILE "/dev/nvram"
+
+///////////////////////////////////////////////////////////////////////
+// Utilities for quick python-C translation
+
+using std::string;
+
+// Works like throwing an exception - directly exit here.
+static void RebootModeError(const char *message, ...) {
+ va_list args;
+ va_start(args, message);
+ vfprintf(stderr, message, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+ exit(1);
+}
+
+// return a string which is upper case of input parameter.
+static string str_to_upper(const string str) {
+ string newstr = str;
+ std::transform(str.begin(), str.end(), newstr.begin(), toupper);
+ return newstr;
+}
+
+///////////////////////////////////////////////////////////////////////
+
+typedef std::map<string, uint8_t> RDB_BitField;
+
+struct RebootModeConfig {
+ // file path
+ string acpi_file;
+ string nvram_file;
+
+ // Offset of RDB in NVRAM
+ int rdb_offset;
+
+ // NVRAM contents read on startup
+ uint8_t rdb_value;
+
+ // A dictionary of fields to be updated as requested by the command line
+ // parameters
+ RDB_BitField fields_to_set;
+
+ // All bitfields in RDB this script provides access to. Field names prepended
+ // by `--' become this script's command line options
+ RDB_BitField all_mode_fields;
+
+ // write constructure here to ease python translation
+ RebootModeConfig() {
+ acpi_file = DEFAULT_ACPI_FILE;
+ nvram_file = DEFAULT_NVRAM_FILE;
+ rdb_offset = 0;
+ all_mode_fields["recovery"] = 0x80;
+ all_mode_fields["debug_reset"] = 0x40;
+ all_mode_fields["try_firmware_b"] = 0x20;
+ }
+} cfg; // this is a special global object to ease python translation.
+
+// 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.
+void OptionHandler(const char *opt_str, const char *value_str) {
+ const char *key = opt_str;
+ int value = atoi(value_str);
+
+ if (!value && *value_str != '0')
+ RebootModeError("--%s needs numeric argument value", key);
+
+ if (value < 0 || value > 1)
+ RebootModeError("--%s should be either 0 or 1", key);
+
+ if (cfg.all_mode_fields.find(key) == cfg.all_mode_fields.end())
+ RebootModeError("INTERNAL ERROR: UNKNOWN FIELD: %s", key);
+
+ cfg.fields_to_set[key] = value;
+}
+
+void GetRDBOffset() {
+ const char *acpi_file = cfg.acpi_file.c_str();
+
+ FILE *f = fopen(acpi_file, "rb");
+ if (!f) {
+ perror(acpi_file);
+ RebootModeError("Cannot read acpi_file: %s", acpi_file);
+ }
+
+ char buffer[PATH_MAX]; // this should be large enough
+ if (fgets(buffer, sizeof(buffer), f) == NULL) {
+ perror(acpi_file);
+ RebootModeError("Trying to read %s but failed.", acpi_file);
+ }
+
+ cfg.rdb_offset = atoi(buffer);
+ if (!cfg.rdb_offset && *buffer != '0') { // consider this as error
+ RebootModeError("%s contents are corrupted", acpi_file);
+ }
+}
+
+void ReadNvram() {
+ FILE *f = fopen(cfg.nvram_file.c_str(), "rb");
+ if (!f) {
+ if (errno == 2)
+ RebootModeError("%s does not exist. Is nvram module installed?",
+ cfg.nvram_file.c_str());
+ if (errno == 13)
+ RebootModeError("Access to %s denied. Are you root?",
+ cfg.nvram_file.c_str());
+ // all other error
+ perror(cfg.nvram_file.c_str());
+ }
+
+ if (fseek(f, cfg.rdb_offset, SEEK_SET) == -1 ||
+ fread(&cfg.rdb_value, 1, 1, f) != 1) {
+ perror(cfg.nvram_file.c_str());
+ RebootModeError("Failed reading mode byte from %s", cfg.nvram_file.c_str());
+ }
+ fclose(f);
+}
+
+void PrintCurrentMode() {
+ printf("Current reboot mode settings:\n");
+ for (RDB_BitField::iterator i = cfg.all_mode_fields.begin();
+ i != cfg.all_mode_fields.end();
+ ++i) {
+ printf("%-15s: %d\n", i->first.c_str(),
+ (cfg.rdb_value & i->second) ? 1 : 0);
+ }
+}
+
+void SetNewMode() {
+ uint8_t new_mode = 0;
+ uint8_t updated_bits_mask = 0;
+
+ for (RDB_BitField::iterator i = cfg.fields_to_set.begin();
+ i != cfg.fields_to_set.end();
+ ++i) {
+ string opt = i->first;
+ uint8_t value = i->second;
+ assert(cfg.all_mode_fields.find(opt) != cfg.all_mode_fields.end());
+
+ uint8_t mask = cfg.all_mode_fields[opt];
+ if (value)
+ new_mode |= mask;
+
+ updated_bits_mask |= mask;
+ }
+
+ if ((cfg.rdb_value & updated_bits_mask) == new_mode) {
+ printf("No update required\n");
+ return;
+ }
+
+ FILE *f = fopen(cfg.nvram_file.c_str(), "rb+");
+ fseek(f, cfg.rdb_offset, SEEK_SET);
+ new_mode |= (cfg.rdb_value & ~updated_bits_mask);
+ if (fwrite(&new_mode, 1, 1, f) != 1) {
+ RebootModeError("Failed writing mode byte to %s", cfg.nvram_file.c_str());
+ }
+ fclose(f);
+}
+
+const char *__name__;
+
+void usage_help_exit(int err) {
+ printf("Usage: %s [options]\n"
+ "\n"
+ "Options:\n"
+ " -h, --help\t\tshow this help message and exit\n"
+ " --acpi_file=ACPI_FILE\n"
+ " --nvram_file=NVRAM_FILE\n"
+ , __name__);
+
+ // list all possible fields
+ for (RDB_BitField::iterator i = cfg.all_mode_fields.begin();
+ i != cfg.all_mode_fields.end();
+ ++i) {
+ printf(" --%s=%s\n",
+ i->first.c_str(),
+ str_to_upper(i->first).c_str());
+ }
+ exit(err);
+}
+
+int main(int argc, char *argv[]) {
+ __name__ = argv[0];
+
+ struct option optv = {0};
+ std::vector<struct option> longopts;
+ int max_field_index = 0;
+
+ optv.has_arg = 0;
+ optv.val = 0;
+ optv.name = "help"; // value = 0
+ longopts.push_back(optv);
+ optv.has_arg = 1;
+
+ optv.val++;
+ optv.name = "acpi_file"; // value = 1
+ longopts.push_back(optv);
+ optv.val++;
+ optv.name = "nvram_file"; // value = 2
+ longopts.push_back(optv);
+
+ // add all known RDB fields
+ for (RDB_BitField::iterator i = cfg.all_mode_fields.begin();
+ i != cfg.all_mode_fields.end();
+ ++i) {
+ optv.name = i->first.c_str();
+ optv.val++;
+ longopts.push_back(optv);
+ }
+ max_field_index = optv.val;
+
+ // add a zero for closing options
+ optv.name = NULL;
+ optv.val = optv.has_arg = 0;
+ longopts.push_back(optv);
+
+ int optc;
+ while ((optc = getopt_long(argc, argv, "h", &longopts.front(), NULL)) != -1) {
+ switch (optc) {
+ case 1:
+ cfg.acpi_file = optarg;
+ break;
+
+ case 2:
+ cfg.nvram_file = optarg;
+ break;
+
+ default:
+ // RDB fields?
+ // printf("optc: %d %s %s\n", optc, longopts[optc].name, optarg);
+ if (optc > 0 && optc <= max_field_index)
+ OptionHandler(longopts[optc].name, optarg);
+ else
+ usage_help_exit(1);
+ break;
+ }
+ }
+
+ // currently no other non-dashed arguments allowed.
+ if (optind != argc)
+ usage_help_exit(1);
+
+ GetRDBOffset();
+ ReadNvram();
+
+ if (!cfg.fields_to_set.empty()) {
+ SetNewMode();
+ } else {
+ PrintCurrentMode();
+ }
+ return 0;
+}
« no previous file with comments | « gpio_setup.py ('k') | reboot_mode.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698