summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2011-04-07 10:37:44 -0700
committerHung-Te Lin <hungte@chromium.org>2011-05-06 12:36:43 -0700
commit4953fda38f67baefcaa592390574129c0ec25f57 (patch)
tree03c46cc795f8a13065c08920f11e8d5f71d37b19
parentc3fe59f72c95597a2d5becc8511e9d5eaf97c391 (diff)
downloadvboot-4953fda38f67baefcaa592390574129c0ec25f57.tar.gz
Add crossystem arch (merge from ToT to R12 factory branch_
This CL is a cherry pick of: Add dummy crossystem_arch implementation for amd64 (host) Change-Id: Ia87cdd9551af1d592ece641c2abcc02db73869e1 Add default arch to fix compiling outside emake Change-Id: I225c2ee7e703aad961c50ec8988ed2466886f266 Review URL: http://codereview.chromium.org/6820018 Add crossystem arch (reports x86 or arm, depending on platform) Change-Id: I857ead5b108d42195145cdbc5cdafa817f3416b4 Review URL: http://codereview.chromium.org/6813054 BUG=none # porting since latest factory tools need to use "crossystem arch" TEST=crossystem arch # see x86 Change-Id: I5049fb7bf88f1cb0cb36ff85813e5a79d2d85d56 Reviewed-on: http://gerrit.chromium.org/gerrit/425 Reviewed-by: Randall Spangler <rspangler@chromium.org> Tested-by: Hung-Te Lin <hungte@chromium.org>
-rw-r--r--Makefile5
-rw-r--r--host/Makefile2
-rw-r--r--host/arch/amd64/lib/crossystem_arch.c57
-rw-r--r--host/arch/arm/lib/crossystem_arch.c108
-rw-r--r--host/arch/x86/lib/crossystem_arch.c593
-rw-r--r--host/include/crossystem_arch.h80
-rw-r--r--host/include/host_misc.h19
-rw-r--r--host/lib/crossystem.c652
-rw-r--r--host/lib/host_misc.c47
-rw-r--r--utility/crossystem_main.c1
10 files changed, 960 insertions, 604 deletions
diff --git a/Makefile b/Makefile
index d12639d0..f1c4b601 100644
--- a/Makefile
+++ b/Makefile
@@ -20,6 +20,11 @@ ifneq (${FIRMWARE_CONFIG_PATH},)
include ${FIRMWARE_CONFIG_PATH}
endif
+# Fix compiling directly on host (outside of emake)
+ifeq ($(ARCH),)
+export ARCH=amd64
+endif
+
ifeq ($(FIRMWARE_ARCH),)
CFLAGS += -DCHROMEOS_ENVIRONMENT
endif
diff --git a/host/Makefile b/host/Makefile
index 3226ac38..7c2866b3 100644
--- a/host/Makefile
+++ b/host/Makefile
@@ -8,12 +8,14 @@ BUILD_ROOT := ${BUILD}/$(shell basename ${HOSTTOP})
INCLUDES += \
-I$(HOSTTOP)/include \
+ -I$(HOSTTOP)/arch/$(ARCH)/include \
-I$(FWDIR)/lib/include \
-I$(FWDIR)/lib/cgptlib/include \
-I$(FWDIR)/lib/cryptolib/include
# find ./lib -iname '*.c' | sort
LIB_SRCS = \
+ ./arch/$(ARCH)/lib/crossystem_arch.c \
./lib/crossystem.c \
./lib/file_keys.c \
./lib/fmap.c \
diff --git a/host/arch/amd64/lib/crossystem_arch.c b/host/arch/amd64/lib/crossystem_arch.c
new file mode 100644
index 00000000..08ae723a
--- /dev/null
+++ b/host/arch/amd64/lib/crossystem_arch.c
@@ -0,0 +1,57 @@
+/* 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.
+ */
+/* crossystem is only valid on devices, not on the host, but since
+ * it's part of the host library, we need a dummy implementation (all
+ * functions return errors) */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include "host_common.h"
+
+#include "crossystem.h"
+#include "crossystem_arch.h"
+#include "utility.h"
+#include "vboot_common.h"
+#include "vboot_nvstorage.h"
+#include "vboot_struct.h"
+
+int VbReadNvStorage(VbNvContext* vnc) {
+ return -1;
+}
+
+
+int VbWriteNvStorage(VbNvContext* vnc) {
+ return -1;
+}
+
+
+VbSharedDataHeader* VbSharedDataRead(void) {
+ return NULL;
+}
+
+
+int VbGetArchPropertyInt(const char* name) {
+ return -1;
+}
+
+
+const char* VbGetArchPropertyString(const char* name, char* dest, int size) {
+ return NULL;
+}
+
+
+int VbSetArchPropertyInt(const char* name, int value) {
+ return -1;
+}
+
+
+int VbSetArchPropertyString(const char* name, const char* value) {
+ return -1;
+}
diff --git a/host/arch/arm/lib/crossystem_arch.c b/host/arch/arm/lib/crossystem_arch.c
new file mode 100644
index 00000000..4304ce7c
--- /dev/null
+++ b/host/arch/arm/lib/crossystem_arch.c
@@ -0,0 +1,108 @@
+/* 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include "host_common.h"
+
+#include "crossystem.h"
+#include "crossystem_arch.h"
+#include "utility.h"
+#include "vboot_common.h"
+#include "vboot_nvstorage.h"
+#include "vboot_struct.h"
+
+
+int VbReadNvStorage(VbNvContext* vnc) {
+ /* TODO: IMPLEMENT ME! */
+ return -1;
+}
+
+
+int VbWriteNvStorage(VbNvContext* vnc) {
+ /* TODO: IMPLEMENT ME! */
+ return -1;
+}
+
+
+VbSharedDataHeader* VbSharedDataRead(void) {
+ /* TODO: IMPLEMENT ME! */
+ return NULL;
+}
+
+
+int VbGetArchPropertyInt(const char* name) {
+
+ /* TODO: IMPLEMENT ME! For now, return reasonable defaults for
+ * values where reasonable defaults exist. */
+ if (!strcasecmp(name,"recovery_reason")) {
+ } else if (!strcasecmp(name,"fmap_base")) {
+ }
+ /* Switch positions */
+ else if (!strcasecmp(name,"devsw_cur")) {
+ return 1;
+ } else if (!strcasecmp(name,"recoverysw_cur")) {
+ return 0;
+ } else if (!strcasecmp(name,"wpsw_cur")) {
+ return 1;
+ } else if (!strcasecmp(name,"devsw_boot")) {
+ return 1;
+ } else if (!strcasecmp(name,"recoverysw_boot")) {
+ return 0;
+ } else if (!strcasecmp(name,"recoverysw_ec_boot")) {
+ return 0;
+ } else if (!strcasecmp(name,"wpsw_boot")) {
+ return 1;
+ }
+
+ /* Saved memory is at a fixed location for all H2C BIOS. If the CHSW
+ * path exists in sysfs, it's a H2C BIOS. */
+ else if (!strcasecmp(name,"savedmem_base")) {
+ } else if (!strcasecmp(name,"savedmem_size")) {
+ }
+
+ return -1;
+}
+
+
+const char* VbGetArchPropertyString(const char* name, char* dest, int size) {
+ /* TODO: IMPLEMENT ME! For now, return reasonable defaults for
+ * values where reasonable defaults exist. */
+ if (!strcasecmp(name,"arch")) {
+ return StrCopy(dest, "arm", size);
+ } else if (!strcasecmp(name,"hwid")) {
+ return StrCopy(dest, "UnknownArmHwid", size);
+ } else if (!strcasecmp(name,"fwid")) {
+ return StrCopy(dest, "UnknownArmFwid", size);
+ } else if (!strcasecmp(name,"ro_fwid")) {
+ return StrCopy(dest, "UnknownArmRoFwid", size);
+ } else if (!strcasecmp(name,"mainfw_act")) {
+ return StrCopy(dest, "A", size);
+ } else if (!strcasecmp(name,"mainfw_type")) {
+ return StrCopy(dest, "developer", size);
+ } else if (!strcasecmp(name,"ecfw_act")) {
+ return StrCopy(dest, "RO", size);
+ }
+
+ return NULL;
+}
+
+
+int VbSetArchPropertyInt(const char* name, int value) {
+ /* TODO: IMPLEMENT ME! */
+ return -1;
+}
+
+
+int VbSetArchPropertyString(const char* name, const char* value) {
+ /* If there were settable architecture-dependent string properties,
+ * they'd be here. */
+ return -1;
+}
diff --git a/host/arch/x86/lib/crossystem_arch.c b/host/arch/x86/lib/crossystem_arch.c
new file mode 100644
index 00000000..b8e6add5
--- /dev/null
+++ b/host/arch/x86/lib/crossystem_arch.c
@@ -0,0 +1,593 @@
+/* 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include "host_common.h"
+
+#include "crossystem.h"
+#include "crossystem_arch.h"
+#include "utility.h"
+#include "vboot_common.h"
+#include "vboot_nvstorage.h"
+#include "vboot_struct.h"
+
+
+/* ACPI constants from Chrome OS Main Processor Firmware Spec */
+/* Boot reasons from BINF.0, from early H2C firmware */
+/* Unknown */
+#define BINF0_UNKNOWN 0
+/* Normal boot to Chrome OS */
+#define BINF0_NORMAL 1
+/* Developer mode boot (developer mode warning displayed) */
+#define BINF0_DEVELOPER 2
+/* Recovery initiated by user, using recovery button */
+#define BINF0_RECOVERY_BUTTON 3
+/* Recovery initiated by user pressing a key at developer mode warning
+ * screen */
+#define BINF0_RECOVERY_DEV_SCREEN_KEY 4
+/* Recovery caused by BIOS failed signature check (neither rewritable
+ * firmware was valid) */
+#define BINF0_RECOVERY_RW_FW_BAD 5
+/* Recovery caused by no OS kernel detected */
+#define BINF0_RECOVERY_NO_OS 6
+/* Recovery caused by OS kernel failed signature check */
+#define BINF0_RECOVERY_BAD_OS 7
+/* Recovery initiated by OS */
+#define BINF0_RECOVERY_OS_INITIATED 8
+/* OS-initiated S3 diagnostic path (debug mode boot) */
+#define BINF0_S3_DIAGNOSTIC_PATH 9
+/* S3 resume failed */
+#define BINF0_S3_RESUME_FAILED 10
+/* Recovery caused by TPM error */
+#define BINF0_RECOVERY_TPM_ERROR 11
+/* Firmware types from BINF.3 */
+#define BINF3_RECOVERY 0
+#define BINF3_NORMAL 1
+#define BINF3_DEVELOPER 2
+/* CHSW bitflags */
+#define CHSW_RECOVERY_BOOT 0x00000002
+#define CHSW_RECOVERY_EC_BOOT 0x00000004
+#define CHSW_DEV_BOOT 0x00000020
+#define CHSW_WP_BOOT 0x00000200
+/* CMOS reboot field bitflags */
+#define CMOSRF_RECOVERY 0x80
+#define CMOSRF_DEBUG_RESET 0x40
+#define CMOSRF_TRY_B 0x20
+/* GPIO signal types */
+#define GPIO_SIGNAL_TYPE_RECOVERY 1
+#define GPIO_SIGNAL_TYPE_DEV 2
+#define GPIO_SIGNAL_TYPE_WP 3
+
+/* Base name for ACPI files */
+#define ACPI_BASE_PATH "/sys/devices/platform/chromeos_acpi"
+/* Paths for frequently used ACPI files */
+#define ACPI_BINF_PATH ACPI_BASE_PATH "/BINF"
+#define ACPI_CHNV_PATH ACPI_BASE_PATH "/CHNV"
+#define ACPI_CHSW_PATH ACPI_BASE_PATH "/CHSW"
+#define ACPI_FMAP_PATH ACPI_BASE_PATH "/FMAP"
+#define ACPI_GPIO_PATH ACPI_BASE_PATH "/GPIO"
+#define ACPI_VBNV_PATH ACPI_BASE_PATH "/VBNV"
+#define ACPI_VDAT_PATH ACPI_BASE_PATH "/VDAT"
+
+/* Base name for GPIO files */
+#define GPIO_BASE_PATH "/sys/class/gpio"
+#define GPIO_EXPORT_PATH GPIO_BASE_PATH "/export"
+
+/* Filename for NVRAM file */
+#define NVRAM_PATH "/dev/nvram"
+
+
+int VbReadNvStorage(VbNvContext* vnc) {
+ FILE* f;
+ int offs;
+
+ /* Get the byte offset from VBNV */
+ offs = ReadFileInt(ACPI_VBNV_PATH ".0");
+ if (offs == -1)
+ return -1;
+ if (VBNV_BLOCK_SIZE > ReadFileInt(ACPI_VBNV_PATH ".1"))
+ return -1; /* NV storage block is too small */
+
+ f = fopen(NVRAM_PATH, "rb");
+ if (!f)
+ return -1;
+
+ if (0 != fseek(f, offs, SEEK_SET) ||
+ 1 != fread(vnc->raw, VBNV_BLOCK_SIZE, 1, f)) {
+ fclose(f);
+ return -1;
+ }
+
+ fclose(f);
+ return 0;
+}
+
+
+int VbWriteNvStorage(VbNvContext* vnc) {
+ FILE* f;
+ int offs;
+
+ if (!vnc->raw_changed)
+ return 0; /* Nothing changed, so no need to write */
+
+ /* Get the byte offset from VBNV */
+ offs = ReadFileInt(ACPI_VBNV_PATH ".0");
+ if (offs == -1)
+ return -1;
+ if (VBNV_BLOCK_SIZE > ReadFileInt(ACPI_VBNV_PATH ".1"))
+ return -1; /* NV storage block is too small */
+
+ f = fopen(NVRAM_PATH, "w+b");
+ if (!f)
+ return -1;
+
+ if (0 != fseek(f, offs, SEEK_SET) ||
+ 1 != fwrite(vnc->raw, VBNV_BLOCK_SIZE, 1, f)) {
+ fclose(f);
+ return -1;
+ }
+
+ fclose(f);
+ return 0;
+}
+
+
+/*
+ * Get buffer data from ACPI.
+ *
+ * Buffer data is expected to be represented by a file which is a text dump of
+ * the buffer, representing each byte by two hex numbers, space and newline
+ * separated.
+ *
+ * On success, stores the amount of data read in bytes to *buffer_size; on
+ * erros, sets *buffer_size=0.
+ *
+ * Input - ACPI file name to get data from.
+ *
+ * Output: a pointer to AcpiBuffer structure containing the binary
+ * representation of the data. The caller is responsible for
+ * deallocating the pointer, this will take care of both the structure
+ * and the buffer. Null in case of error.
+ */
+static uint8_t* VbGetBuffer(const char* filename, int* buffer_size)
+{
+ FILE* f = NULL;
+ char* file_buffer = NULL;
+ uint8_t* output_buffer = NULL;
+ uint8_t* return_value = NULL;
+
+ /* Assume error until proven otherwise */
+ if (buffer_size)
+ *buffer_size = 0;
+
+ do {
+ struct stat fs;
+ uint8_t* output_ptr;
+ int rv, i, real_size;
+ int parsed_size = 0;
+
+ rv = stat(filename, &fs);
+ if (rv || !S_ISREG(fs.st_mode))
+ break;
+
+ f = fopen(filename, "r");
+ if (!f)
+ break;
+
+ file_buffer = Malloc(fs.st_size + 1);
+ if (!file_buffer)
+ break;
+
+ real_size = fread(file_buffer, 1, fs.st_size, f);
+ if (!real_size)
+ break;
+ file_buffer[real_size] = '\0';
+
+ /* Each byte in the output will replace two characters and a space
+ * in the input, so the output size does not exceed input side/3
+ * (a little less if account for newline characters). */
+ output_buffer = Malloc(real_size/3);
+ if (!output_buffer)
+ break;
+ output_ptr = output_buffer;
+
+ /* process the file contents */
+ for (i = 0; i < real_size; i++) {
+ char* base, *end;
+
+ base = file_buffer + i;
+
+ if (!isxdigit(*base))
+ continue;
+
+ output_ptr[parsed_size++] = strtol(base, &end, 16) & 0xff;
+
+ if ((end - base) != 2)
+ /* Input file format error */
+ break;
+
+ i += 2; /* skip the second character and the following space */
+ }
+
+ if (i == real_size) {
+ /* all is well */
+ return_value = output_buffer;
+ output_buffer = NULL; /* prevent it from deallocating */
+ if (buffer_size)
+ *buffer_size = parsed_size;
+ }
+ } while(0);
+
+ /* wrap up */
+ if (f)
+ fclose(f);
+
+ if (file_buffer)
+ Free(file_buffer);
+
+ if (output_buffer)
+ Free(output_buffer);
+
+ return return_value;
+}
+
+
+VbSharedDataHeader* VbSharedDataRead(void) {
+
+ VbSharedDataHeader* sh;
+ int got_size = 0;
+
+ sh = (VbSharedDataHeader*)VbGetBuffer(ACPI_VDAT_PATH, &got_size);
+ if (!sh)
+ return NULL;
+ if (got_size < sizeof(VbSharedDataHeader)) {
+ Free(sh);
+ return NULL;
+ }
+ if (sh->data_size > got_size)
+ sh->data_size = got_size; /* Truncated read */
+
+ return sh;
+}
+
+
+/* Read the CMOS reboot field in NVRAM.
+ *
+ * Returns 0 if the mask is clear in the field, 1 if set, or -1 if error. */
+static int VbGetCmosRebootField(uint8_t mask) {
+ FILE* f;
+ int chnv, nvbyte;
+
+ /* Get the byte offset from CHNV */
+ chnv = ReadFileInt(ACPI_CHNV_PATH);
+ if (chnv == -1)
+ return -1;
+
+ f = fopen(NVRAM_PATH, "rb");
+ if (!f)
+ return -1;
+
+ if (0 != fseek(f, chnv, SEEK_SET) || EOF == (nvbyte = fgetc(f))) {
+ fclose(f);
+ return -1;
+ }
+
+ fclose(f);
+ return (nvbyte & mask ? 1 : 0);
+}
+
+
+/* Write the CMOS reboot field in NVRAM.
+ *
+ * Sets (value=0) or clears (value!=0) the mask in the byte.
+ *
+ * Returns 0 if success, or -1 if error. */
+static int VbSetCmosRebootField(uint8_t mask, int value) {
+ FILE* f;
+ int chnv, nvbyte;
+
+ /* Get the byte offset from CHNV */
+ chnv = ReadFileInt(ACPI_CHNV_PATH);
+ if (chnv == -1)
+ return -1;
+
+ f = fopen(NVRAM_PATH, "w+b");
+ if (!f)
+ return -1;
+
+ /* Read the current value */
+ if (0 != fseek(f, chnv, SEEK_SET) || EOF == (nvbyte = fgetc(f))) {
+ fclose(f);
+ return -1;
+ }
+
+ /* Set/clear the mask */
+ if (value)
+ nvbyte |= mask;
+ else
+ nvbyte &= ~mask;
+
+ /* Write the byte back */
+ if (0 != fseek(f, chnv, SEEK_SET) || EOF == (fputc(nvbyte, f))) {
+ fclose(f);
+ return -1;
+ }
+
+ /* Success */
+ fclose(f);
+ return 0;
+}
+
+
+/* Read the active main firmware type into the destination buffer.
+ * Passed the destination and its size. Returns the destination, or
+ * NULL if error. */
+static const char* VbReadMainFwType(char* dest, int size) {
+
+ /* Try reading type from BINF.3 */
+ switch(ReadFileInt(ACPI_BINF_PATH ".3")) {
+ case BINF3_RECOVERY:
+ return StrCopy(dest, "recovery", size);
+ case BINF3_NORMAL:
+ return StrCopy(dest, "normal", size);
+ case BINF3_DEVELOPER:
+ return StrCopy(dest, "developer", size);
+ default:
+ break; /* Fall through to legacy handling */
+ }
+
+ /* Fall back to BINF.0 for legacy systems like Mario. */
+ switch(ReadFileInt(ACPI_BINF_PATH ".0")) {
+ case -1:
+ /* Both BINF.0 and BINF.3 are missing, so this isn't Chrome OS
+ * firmware. */
+ return StrCopy(dest, "nonchrome", size);
+ case BINF0_NORMAL:
+ return StrCopy(dest, "normal", size);
+ case BINF0_DEVELOPER:
+ return StrCopy(dest, "developer", size);
+ case BINF0_RECOVERY_BUTTON:
+ case BINF0_RECOVERY_DEV_SCREEN_KEY:
+ case BINF0_RECOVERY_RW_FW_BAD:
+ case BINF0_RECOVERY_NO_OS:
+ case BINF0_RECOVERY_BAD_OS:
+ case BINF0_RECOVERY_OS_INITIATED:
+ case BINF0_RECOVERY_TPM_ERROR:
+ /* Assorted flavors of recovery boot reason. */
+ return StrCopy(dest, "recovery", size);
+ default:
+ /* Other values don't map cleanly to firmware type. */
+ return NULL;
+ }
+}
+
+
+/* Read the recovery reason. Returns the reason code or -1 if error. */
+static int VbGetRecoveryReason(void) {
+ int value;
+
+ /* Try reading type from BINF.4 */
+ value = ReadFileInt(ACPI_BINF_PATH ".4");
+ if (-1 != value)
+ return value;
+
+ /* Fall back to BINF.0 for legacy systems like Mario. */
+ switch(ReadFileInt(ACPI_BINF_PATH ".0")) {
+ case BINF0_NORMAL:
+ case BINF0_DEVELOPER:
+ return VBNV_RECOVERY_NOT_REQUESTED;
+ case BINF0_RECOVERY_BUTTON:
+ return VBNV_RECOVERY_RO_MANUAL;
+ case BINF0_RECOVERY_DEV_SCREEN_KEY:
+ return VBNV_RECOVERY_RW_DEV_SCREEN;
+ case BINF0_RECOVERY_RW_FW_BAD:
+ case BINF0_RECOVERY_NO_OS:
+ return VBNV_RECOVERY_RW_NO_OS;
+ case BINF0_RECOVERY_BAD_OS:
+ return VBNV_RECOVERY_RW_INVALID_OS;
+ case BINF0_RECOVERY_OS_INITIATED:
+ return VBNV_RECOVERY_LEGACY;
+ default:
+ /* Other values don't map cleanly to firmware type. */
+ return -1;
+ }
+}
+
+
+/* Read a GPIO of the specified signal type (see ACPI GPIO SignalType).
+ *
+ * Returns 1 if the signal is asserted, 0 if not asserted, or -1 if error. */
+static int ReadGpio(int signal_type) {
+ char name[128];
+ int index = 0;
+ int gpio_type;
+ int active_high;
+ int controller_offset;
+ char controller_name[128];
+ int value;
+
+ /* Scan GPIO.* to find a matching signal type */
+ for (index = 0; ; index++) {
+ snprintf(name, sizeof(name), "%s.%d/GPIO.0", ACPI_GPIO_PATH, index);
+ gpio_type = ReadFileInt(name);
+ if (gpio_type == signal_type)
+ break;
+ else if (gpio_type == -1)
+ return -1; /* Ran out of GPIOs before finding a match */
+ }
+
+ /* Read attributes and controller info for the GPIO */
+ snprintf(name, sizeof(name), "%s.%d/GPIO.1", ACPI_GPIO_PATH, index);
+ active_high = ReadFileBit(name, 0x00000001);
+ snprintf(name, sizeof(name), "%s.%d/GPIO.2", ACPI_GPIO_PATH, index);
+ controller_offset = ReadFileInt(name);
+ if (active_high == -1 || controller_offset == -1)
+ return -1; /* Missing needed info */
+
+ /* We only support the NM10 for now */
+ snprintf(name, sizeof(name), "%s.%d/GPIO.3", ACPI_GPIO_PATH, index);
+ if (!ReadFileString(controller_name, sizeof(controller_name), name))
+ return -1;
+ if (0 != strcmp(controller_name, "NM10"))
+ return -1;
+
+ /* Assume the NM10 has offset 192 */
+ /* TODO: should really check gpiochipNNN/label to see if it's the
+ * address we expect for the NM10, and then read the offset from
+ * gpiochipNNN/base. */
+ controller_offset += 192;
+
+ /* Try reading the GPIO value */
+ snprintf(name, sizeof(name), "%s/gpio%d/value",
+ GPIO_BASE_PATH, controller_offset);
+ value = ReadFileInt(name);
+
+ if (value == -1) {
+ /* Try exporting the GPIO */
+ FILE* f = fopen(GPIO_EXPORT_PATH, "wt");
+ if (!f)
+ return -1;
+ fprintf(f, "%d", controller_offset);
+ fclose(f);
+
+ /* Try re-reading the GPIO value */
+ value = ReadFileInt(name);
+ }
+
+ if (value == -1)
+ return -1;
+
+ /* Compare the GPIO value with the active value and return 1 if match. */
+ return (value == active_high ? 1 : 0);
+}
+
+
+int VbGetArchPropertyInt(const char* name) {
+ int value = -1;
+
+ /* Values from ACPI */
+ if (!strcasecmp(name,"recovery_reason")) {
+ value = VbGetRecoveryReason();
+ } else if (!strcasecmp(name,"fmap_base")) {
+ value = ReadFileInt(ACPI_FMAP_PATH);
+ }
+ /* Switch positions */
+ else if (!strcasecmp(name,"devsw_cur")) {
+ value = ReadGpio(GPIO_SIGNAL_TYPE_DEV);
+ } else if (!strcasecmp(name,"recoverysw_cur")) {
+ value = ReadGpio(GPIO_SIGNAL_TYPE_RECOVERY);
+ } else if (!strcasecmp(name,"wpsw_cur")) {
+ value = ReadGpio(GPIO_SIGNAL_TYPE_WP);
+ if (-1 != value && FwidStartsWith("Mario."))
+ value = 1 - value; /* Mario reports this backwards */
+ } else if (!strcasecmp(name,"devsw_boot")) {
+ value = ReadFileBit(ACPI_CHSW_PATH, CHSW_DEV_BOOT);
+ } else if (!strcasecmp(name,"recoverysw_boot")) {
+ value = ReadFileBit(ACPI_CHSW_PATH, CHSW_RECOVERY_BOOT);
+ } else if (!strcasecmp(name,"recoverysw_ec_boot")) {
+ value = ReadFileBit(ACPI_CHSW_PATH, CHSW_RECOVERY_EC_BOOT);
+ } else if (!strcasecmp(name,"wpsw_boot")) {
+ value = ReadFileBit(ACPI_CHSW_PATH, CHSW_WP_BOOT);
+ if (-1 != value && FwidStartsWith("Mario."))
+ value = 1 - value; /* Mario reports this backwards */
+ }
+
+ /* Saved memory is at a fixed location for all H2C BIOS. If the CHSW
+ * path exists in sysfs, it's a H2C BIOS. */
+ else if (!strcasecmp(name,"savedmem_base")) {
+ return (-1 == ReadFileInt(ACPI_CHSW_PATH) ? -1 : 0x00F00000);
+ } else if (!strcasecmp(name,"savedmem_size")) {
+ return (-1 == ReadFileInt(ACPI_CHSW_PATH) ? -1 : 0x00100000);
+ }
+ /* NV storage values. If unable to get from NV storage, fall back to the
+ * CMOS reboot field used by older BIOS. */
+ else if (!strcasecmp(name,"recovery_request")) {
+ value = VbGetNvStorage(VBNV_RECOVERY_REQUEST);
+ if (-1 == value)
+ value = VbGetCmosRebootField(CMOSRF_RECOVERY);
+ } else if (!strcasecmp(name,"dbg_reset")) {
+ value = VbGetNvStorage(VBNV_DEBUG_RESET_MODE);
+ if (-1 == value)
+ value = VbGetCmosRebootField(CMOSRF_DEBUG_RESET);
+ } else if (!strcasecmp(name,"fwb_tries")) {
+ value = VbGetNvStorage(VBNV_TRY_B_COUNT);
+ if (-1 == value)
+ value = VbGetCmosRebootField(CMOSRF_TRY_B);
+ }
+
+ return value;
+}
+
+
+const char* VbGetArchPropertyString(const char* name, char* dest, int size) {
+
+ if (!strcasecmp(name,"arch")) {
+ return StrCopy(dest, "x86", size);
+ } else if (!strcasecmp(name,"hwid")) {
+ return ReadFileString(dest, size, ACPI_BASE_PATH "/HWID");
+ } else if (!strcasecmp(name,"fwid")) {
+ return ReadFileString(dest, size, ACPI_BASE_PATH "/FWID");
+ } else if (!strcasecmp(name,"ro_fwid")) {
+ return ReadFileString(dest, size, ACPI_BASE_PATH "/FRID");
+ } else if (!strcasecmp(name,"mainfw_act")) {
+ switch(ReadFileInt(ACPI_BINF_PATH ".1")) {
+ case 0:
+ return StrCopy(dest, "recovery", size);
+ case 1:
+ return StrCopy(dest, "A", size);
+ case 2:
+ return StrCopy(dest, "B", size);
+ default:
+ return NULL;
+ }
+ } else if (!strcasecmp(name,"mainfw_type")) {
+ return VbReadMainFwType(dest, size);
+ } else if (!strcasecmp(name,"ecfw_act")) {
+ switch(ReadFileInt(ACPI_BINF_PATH ".2")) {
+ case 0:
+ return StrCopy(dest, "RO", size);
+ case 1:
+ return StrCopy(dest, "RW", size);
+ default:
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+
+int VbSetArchPropertyInt(const char* name, int value) {
+ /* NV storage values. If unable to get from NV storage, fall back to the
+ * CMOS reboot field used by older BIOS. */
+ if (!strcasecmp(name,"recovery_request")) {
+ if (0 == VbSetNvStorage(VBNV_RECOVERY_REQUEST, value))
+ return 0;
+ return VbSetCmosRebootField(CMOSRF_RECOVERY, value);
+ } else if (!strcasecmp(name,"dbg_reset")) {
+ if (0 == VbSetNvStorage(VBNV_DEBUG_RESET_MODE, value))
+ return 0;
+ return VbSetCmosRebootField(CMOSRF_DEBUG_RESET, value);
+ } else if (!strcasecmp(name,"fwb_tries")) {
+ if (0 == VbSetNvStorage(VBNV_TRY_B_COUNT, value))
+ return 0;
+ return VbSetCmosRebootField(CMOSRF_TRY_B, value);
+ }
+
+ return -1;
+}
+
+
+int VbSetArchPropertyString(const char* name, const char* value) {
+ /* If there were settable architecture-dependent string properties,
+ * they'd be here. */
+ return -1;
+}
diff --git a/host/include/crossystem_arch.h b/host/include/crossystem_arch.h
new file mode 100644
index 00000000..ee8425b4
--- /dev/null
+++ b/host/include/crossystem_arch.h
@@ -0,0 +1,80 @@
+/* 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.
+ *
+ * Architecture-specific APIs for crossystem
+ */
+
+#ifndef VBOOT_REFERENCE_CROSSYSTEM_ARCH_H_
+#define VBOOT_REFERENCE_CROSSYSTEM_ARCH_H_
+
+#include "vboot_nvstorage.h"
+#include "vboot_struct.h"
+
+
+/* INTERNAL APIS FOR CROSSYSTEM AVAILABLE TO ARCH-SPECIFIC FUNCTIONS */
+
+/* Read an integer property from VbNvStorage.
+ *
+ * Returns the parameter value, or -1 if error. */
+int VbGetNvStorage(VbNvParam param);
+
+/* Write an integer property to VbNvStorage.
+ *
+ * Returns 0 if success, -1 if error. */
+int VbSetNvStorage(VbNvParam param, int value);
+
+/* Return true if the FWID starts with the specified string. */
+int FwidStartsWith(const char *start);
+
+
+/* APIS WITH ARCH-SPECIFIC IMPLEMENTATIONS */
+
+/* Read the non-volatile context from NVRAM.
+ *
+ * Returns 0 if success, -1 if error. */
+int VbReadNvStorage(VbNvContext* vnc);
+
+/* Write the non-volatile context to NVRAM.
+ *
+ * Returns 0 if success, -1 if error. */
+int VbWriteNvStorage(VbNvContext* vnc);
+
+/* Read the VbSharedData buffer.
+ *
+ * Verifies the buffer contains at least enough data for the
+ * VbSharedDataHeader; if not, this is an error.
+ *
+ * If less data is read than expected, sets the returned structure's data_size
+ * to the actual amount of data read. If this is less than data_used, then
+ * some data was not returned; callers must handle this; this is not considered
+ * an error.
+ *
+ * Returns the data buffer, which must be freed by the caller, or NULL if
+ * error. */
+VbSharedDataHeader* VbSharedDataRead(void);
+
+/* Read an architecture-specific system property integer.
+ *
+ * Returns the property value, or -1 if error. */
+int VbGetArchPropertyInt(const char* name);
+
+/* Read an architecture-specific system property string into a
+ * destination buffer of the specified size. Returned string will be
+ * null-terminated. If the buffer is too small, the returned string
+ * will be truncated.
+ *
+ * Returns the passed buffer, or NULL if error. */
+const char* VbGetArchPropertyString(const char* name, char* dest, int size);
+
+/* Set an architecture-specific system property integer.
+ *
+ * Returns 0 if success, -1 if error. */
+int VbSetArchPropertyInt(const char* name, int value);
+
+/* Set an architecture-specific system property string.
+ *
+ * Returns 0 if success, -1 if error. */
+int VbSetArchPropertyString(const char* name, const char* value);
+
+#endif /* VBOOT_REFERENCE__CROSSYSTEM_ARCH_H_ */
diff --git a/host/include/host_misc.h b/host/include/host_misc.h
index cbf9eaff..22b31415 100644
--- a/host/include/host_misc.h
+++ b/host/include/host_misc.h
@@ -11,6 +11,10 @@
#include "utility.h"
#include "vboot_struct.h"
+/* Copy up to dest_size-1 characters from src to dest, ensuring null
+ termination (which strncpy() doesn't do). Returns the destination
+ string. */
+char* StrCopy(char* dest, const char* src, int dest_size);
/* Read data from [filename]. Store the size of returned data in [size].
*
@@ -18,6 +22,21 @@
* error. */
uint8_t* ReadFile(const char* filename, uint64_t* size);
+/* Read a string from a file. Passed the destination, dest size, and
+ * filename to read.
+ *
+ * Returns the destination, or NULL if error. */
+char* ReadFileString(char* dest, int size, const char* filename);
+
+/* Read an integer from a file.
+ *
+ * Returns the parsed integer, or -1 if error. */
+int ReadFileInt(const char* filename);
+
+/* Check if a bit is set in a file which contains an integer.
+ *
+ * Returns 1 if the bit is set, 0 if clear, or -1 if error. */
+int ReadFileBit(const char* filename, int bitmask);
/* Writes [size] bytes of [data] to [filename].
*
diff --git a/host/lib/crossystem.c b/host/lib/crossystem.c
index 5c5dec0d..2e29d04d 100644
--- a/host/lib/crossystem.c
+++ b/host/lib/crossystem.c
@@ -13,85 +13,15 @@
#include "host_common.h"
#include "crossystem.h"
+#include "crossystem_arch.h"
#include "utility.h"
#include "vboot_common.h"
#include "vboot_nvstorage.h"
#include "vboot_struct.h"
-/* ACPI constants from Chrome OS Main Processor Firmware Spec */
-/* GPIO signal types */
-#define GPIO_SIGNAL_TYPE_RECOVERY 1
-#define GPIO_SIGNAL_TYPE_DEV 2
-#define GPIO_SIGNAL_TYPE_WP 3
-/* CHSW bitflags */
-#define CHSW_RECOVERY_BOOT 0x00000002
-#define CHSW_RECOVERY_EC_BOOT 0x00000004
-#define CHSW_DEV_BOOT 0x00000020
-#define CHSW_WP_BOOT 0x00000200
-/* CMOS reboot field bitflags */
-#define CMOSRF_RECOVERY 0x80
-#define CMOSRF_DEBUG_RESET 0x40
-#define CMOSRF_TRY_B 0x20
-/* Boot reasons from BINF.0, from early H2C firmware */
-/* Unknown */
-#define BINF0_UNKNOWN 0
-/* Normal boot to Chrome OS */
-#define BINF0_NORMAL 1
-/* Developer mode boot (developer mode warning displayed) */
-#define BINF0_DEVELOPER 2
-/* Recovery initiated by user, using recovery button */
-#define BINF0_RECOVERY_BUTTON 3
-/* Recovery initiated by user pressing a key at developer mode warning
- * screen */
-#define BINF0_RECOVERY_DEV_SCREEN_KEY 4
-/* Recovery caused by BIOS failed signature check (neither rewritable
- * firmware was valid) */
-#define BINF0_RECOVERY_RW_FW_BAD 5
-/* Recovery caused by no OS kernel detected */
-#define BINF0_RECOVERY_NO_OS 6
-/* Recovery caused by OS kernel failed signature check */
-#define BINF0_RECOVERY_BAD_OS 7
-/* Recovery initiated by OS */
-#define BINF0_RECOVERY_OS_INITIATED 8
-/* OS-initiated S3 diagnostic path (debug mode boot) */
-#define BINF0_S3_DIAGNOSTIC_PATH 9
-/* S3 resume failed */
-#define BINF0_S3_RESUME_FAILED 10
-/* Recovery caused by TPM error */
-#define BINF0_RECOVERY_TPM_ERROR 11
-/* Firmware types from BINF.3 */
-#define BINF3_RECOVERY 0
-#define BINF3_NORMAL 1
-#define BINF3_DEVELOPER 2
-
-/* Base name for ACPI files */
-#define ACPI_BASE_PATH "/sys/devices/platform/chromeos_acpi"
-/* Paths for frequently used ACPI files */
-#define ACPI_BINF_PATH ACPI_BASE_PATH "/BINF"
-#define ACPI_CHNV_PATH ACPI_BASE_PATH "/CHNV"
-#define ACPI_CHSW_PATH ACPI_BASE_PATH "/CHSW"
-#define ACPI_FMAP_PATH ACPI_BASE_PATH "/FMAP"
-#define ACPI_GPIO_PATH ACPI_BASE_PATH "/GPIO"
-#define ACPI_VBNV_PATH ACPI_BASE_PATH "/VBNV"
-#define ACPI_VDAT_PATH ACPI_BASE_PATH "/VDAT"
-
-/* Base name for GPIO files */
-#define GPIO_BASE_PATH "/sys/class/gpio"
-#define GPIO_EXPORT_PATH GPIO_BASE_PATH "/export"
-
-/* Filename for NVRAM file */
-#define NVRAM_PATH "/dev/nvram"
-
/* Filename for kernel command line */
#define KERNEL_CMDLINE_PATH "/proc/cmdline"
-/* A structure to contain buffer data retrieved from the ACPI. */
-typedef struct {
- int buffer_size;
- uint8_t* buffer;
-} AcpiBuffer;
-
-
/* Fields that GetVdatString() can get */
typedef enum VdatStringField {
VDAT_STRING_TIMERS = 0, /* Timer values */
@@ -111,67 +41,8 @@ typedef enum VdatIntField {
} VdatIntField;
-/* Copy up to dest_size-1 characters from src to dest, ensuring null
- termination (which strncpy() doesn't do). Returns the destination
- string. */
-char* StrCopy(char* dest, const char* src, int dest_size) {
- strncpy(dest, src, dest_size);
- dest[dest_size - 1] = '\0';
- return dest;
-}
-
-
-/* Read a string from a file. Passed the destination, dest size, and
- * filename to read.
- *
- * Returns the destination, or NULL if error. */
-char* ReadFileString(char* dest, int size, const char* filename) {
- char* got;
- FILE* f;
-
- f = fopen(filename, "rt");
- if (!f)
- return NULL;
-
- got = fgets(dest, size, f);
- fclose(f);
- return got;
-}
-
-
-/* Read an integer from a file.
- *
- * Returns the parsed integer, or -1 if error. */
-int ReadFileInt(const char* filename) {
- char buf[64];
- int value;
- char* e = NULL;
-
- if (!ReadFileString(buf, sizeof(buf), filename))
- return -1;
-
- /* Convert to integer. Allow characters after the int ("123 blah"). */
- value = strtol(buf, &e, 0);
- if (e == buf)
- return -1; /* No characters consumed, so conversion failed */
-
- return value;
-}
-
-
-/* Check if a bit is set in a file which contains an integer.
- *
- * Returns 1 if the bit is set, 0 if clear, or -1 if error. */
-int ReadFileBit(const char* filename, int bitmask) {
- int value = ReadFileInt(filename);
- if (value == -1)
- return -1;
- else return (value & bitmask ? 1 : 0);
-}
-
-
/* Return true if the FWID starts with the specified string. */
-static int FwidStartsWith(const char *start) {
+int FwidStartsWith(const char *start) {
char fwid[128];
if (!VbGetSystemPropertyString("fwid", fwid, sizeof(fwid)))
return 0;
@@ -180,263 +51,15 @@ static int FwidStartsWith(const char *start) {
}
-/* Read a GPIO of the specified signal type (see ACPI GPIO SignalType).
- *
- * Returns 1 if the signal is asserted, 0 if not asserted, or -1 if error. */
-int ReadGpio(int signal_type) {
- char name[128];
- int index = 0;
- int gpio_type;
- int active_high;
- int controller_offset;
- char controller_name[128];
- int value;
-
- /* Scan GPIO.* to find a matching signal type */
- for (index = 0; ; index++) {
- snprintf(name, sizeof(name), "%s.%d/GPIO.0", ACPI_GPIO_PATH, index);
- gpio_type = ReadFileInt(name);
- if (gpio_type == signal_type)
- break;
- else if (gpio_type == -1)
- return -1; /* Ran out of GPIOs before finding a match */
- }
-
- /* Read attributes and controller info for the GPIO */
- snprintf(name, sizeof(name), "%s.%d/GPIO.1", ACPI_GPIO_PATH, index);
- active_high = ReadFileBit(name, 0x00000001);
- snprintf(name, sizeof(name), "%s.%d/GPIO.2", ACPI_GPIO_PATH, index);
- controller_offset = ReadFileInt(name);
- if (active_high == -1 || controller_offset == -1)
- return -1; /* Missing needed info */
-
- /* We only support the NM10 for now */
- snprintf(name, sizeof(name), "%s.%d/GPIO.3", ACPI_GPIO_PATH, index);
- if (!ReadFileString(controller_name, sizeof(controller_name), name))
- return -1;
- if (0 != strcmp(controller_name, "NM10"))
- return -1;
-
- /* Assume the NM10 has offset 192 */
- /* TODO: should really check gpiochipNNN/label to see if it's the
- * address we expect for the NM10, and then read the offset from
- * gpiochipNNN/base. */
- controller_offset += 192;
-
- /* Try reading the GPIO value */
- snprintf(name, sizeof(name), "%s/gpio%d/value",
- GPIO_BASE_PATH, controller_offset);
- value = ReadFileInt(name);
-
- if (value == -1) {
- /* Try exporting the GPIO */
- FILE* f = fopen(GPIO_EXPORT_PATH, "wt");
- if (!f)
- return -1;
- fprintf(f, "%d", controller_offset);
- fclose(f);
-
- /* Try re-reading the GPIO value */
- value = ReadFileInt(name);
- }
-
- if (value == -1)
- return -1;
-
- /* Compare the GPIO value with the active value and return 1 if match. */
- return (value == active_high ? 1 : 0);
-}
-
-
-/* Read the CMOS reboot field in NVRAM.
- *
- * Returns 0 if the mask is clear in the field, 1 if set, or -1 if error. */
-int VbGetCmosRebootField(uint8_t mask) {
- FILE* f;
- int chnv, nvbyte;
-
- /* Get the byte offset from CHNV */
- chnv = ReadFileInt(ACPI_CHNV_PATH);
- if (chnv == -1)
- return -1;
-
- f = fopen(NVRAM_PATH, "rb");
- if (!f)
- return -1;
-
- if (0 != fseek(f, chnv, SEEK_SET) || EOF == (nvbyte = fgetc(f))) {
- fclose(f);
- return -1;
- }
-
- fclose(f);
- return (nvbyte & mask ? 1 : 0);
-}
-
-
-/* Write the CMOS reboot field in NVRAM.
- *
- * Sets (value=0) or clears (value!=0) the mask in the byte.
- *
- * Returns 0 if success, or -1 if error. */
-int VbSetCmosRebootField(uint8_t mask, int value) {
- FILE* f;
- int chnv, nvbyte;
-
- /* Get the byte offset from CHNV */
- chnv = ReadFileInt(ACPI_CHNV_PATH);
- if (chnv == -1)
- return -1;
-
- f = fopen(NVRAM_PATH, "w+b");
- if (!f)
- return -1;
-
- /* Read the current value */
- if (0 != fseek(f, chnv, SEEK_SET) || EOF == (nvbyte = fgetc(f))) {
- fclose(f);
- return -1;
- }
-
- /* Set/clear the mask */
- if (value)
- nvbyte |= mask;
- else
- nvbyte &= ~mask;
-
- /* Write the byte back */
- if (0 != fseek(f, chnv, SEEK_SET) || EOF == (fputc(nvbyte, f))) {
- fclose(f);
- return -1;
- }
-
- /* Success */
- fclose(f);
- return 0;
-}
-
-/*
- * Get buffer data from ACPI.
- *
- * Buffer data is expected to be represented by a file which is a text dump of
- * the buffer, representing each byte by two hex numbers, space and newline
- * separated.
- *
- * Input - ACPI file name to get data from.
- *
- * Output: a pointer to AcpiBuffer structure containing the binary
- * representation of the data. The caller is responsible for
- * deallocating the pointer, this will take care of both the structure
- * and the buffer. Null in case of error.
- */
-
-AcpiBuffer* VbGetBuffer(const char* filename)
-{
- FILE* f = NULL;
- char* file_buffer = NULL;
- AcpiBuffer* acpi_buffer = NULL;
- AcpiBuffer* return_value = NULL;
-
- do {
- struct stat fs;
- uint8_t* output_ptr;
- int rv, i, real_size;
-
- rv = stat(filename, &fs);
- if (rv || !S_ISREG(fs.st_mode))
- break;
-
- f = fopen(filename, "r");
- if (!f)
- break;
-
- file_buffer = Malloc(fs.st_size + 1);
- if (!file_buffer)
- break;
-
- real_size = fread(file_buffer, 1, fs.st_size, f);
- if (!real_size)
- break;
- file_buffer[real_size] = '\0';
-
- /* Each byte in the output will replace two characters and a space
- * in the input, so the output size does not exceed input side/3
- * (a little less if account for newline characters). */
- acpi_buffer = Malloc(sizeof(AcpiBuffer) + real_size/3);
- if (!acpi_buffer)
- break;
- acpi_buffer->buffer = (uint8_t*)(acpi_buffer + 1);
- acpi_buffer->buffer_size = 0;
- output_ptr = acpi_buffer->buffer;
-
- /* process the file contents */
- for (i = 0; i < real_size; i++) {
- char* base, *end;
-
- base = file_buffer + i;
-
- if (!isxdigit(*base))
- continue;
-
- output_ptr[acpi_buffer->buffer_size++] = strtol(base, &end, 16) & 0xff;
-
- if ((end - base) != 2)
- /* Input file format error */
- break;
-
- i += 2; /* skip the second character and the following space */
- }
-
- if (i == real_size) {
- /* all is well */
- return_value = acpi_buffer;
- acpi_buffer = NULL; /* prevent it from deallocating */
- }
- } while(0);
-
- /* wrap up */
- if (f)
- fclose(f);
-
- if (file_buffer)
- Free(file_buffer);
-
- if (acpi_buffer)
- Free(acpi_buffer);
-
- return return_value;
-}
-
-/* Read an integer property from VbNvStorage.
- *
- * Returns the parameter value, or -1 if error. */
int VbGetNvStorage(VbNvParam param) {
- FILE* f;
VbNvContext vnc;
- int offs;
uint32_t value;
int retval;
- /* Get the byte offset from VBNV */
- offs = ReadFileInt(ACPI_VBNV_PATH ".0");
- if (offs == -1)
- return -1;
- if (VBNV_BLOCK_SIZE > ReadFileInt(ACPI_VBNV_PATH ".1"))
- return -1; /* NV storage block is too small */
-
/* TODO: locking around NV access */
- f = fopen(NVRAM_PATH, "rb");
- if (!f)
- return -1;
- if (0 != fseek(f, offs, SEEK_SET) ||
- 1 != fread(vnc.raw, VBNV_BLOCK_SIZE, 1, f)) {
- fclose(f);
+ if (0 != VbReadNvStorage(&vnc))
return -1;
- }
-
- fclose(f);
-
if (0 != VbNvSetup(&vnc))
return -1;
retval = VbNvGet(&vnc, param, &value);
@@ -453,32 +76,13 @@ int VbGetNvStorage(VbNvParam param) {
}
-/* Write an integer property to VbNvStorage.
- *
- * Returns 0 if success, -1 if error. */
int VbSetNvStorage(VbNvParam param, int value) {
- FILE* f;
VbNvContext vnc;
- int offs;
int retval = -1;
int i;
- /* Get the byte offset from VBNV */
- offs = ReadFileInt(ACPI_VBNV_PATH ".0");
- if (offs == -1)
+ if (0 != VbReadNvStorage(&vnc))
return -1;
- if (VBNV_BLOCK_SIZE > ReadFileInt(ACPI_VBNV_PATH ".1"))
- return -1; /* NV storage block is too small */
-
- /* TODO: locking around NV access */
- f = fopen(NVRAM_PATH, "w+b");
- if (!f)
- return -1;
-
- if (0 != fseek(f, offs, SEEK_SET) ||
- 1 != fread(vnc.raw, VBNV_BLOCK_SIZE, 1, f)) {
- goto VbSetNvCleanup;
- }
if (0 != VbNvSetup(&vnc))
goto VbSetNvCleanup;
@@ -489,8 +93,7 @@ int VbSetNvStorage(VbNvParam param, int value) {
goto VbSetNvCleanup;
if (vnc.raw_changed) {
- if (0 != fseek(f, offs, SEEK_SET) ||
- 1 != fwrite(vnc.raw, VBNV_BLOCK_SIZE, 1, f))
+ if (0 != VbReadNvStorage(&vnc))
goto VbSetNvCleanup;
}
@@ -498,101 +101,25 @@ int VbSetNvStorage(VbNvParam param, int value) {
retval = 0;
VbSetNvCleanup:
- fclose(f);
/* TODO: release lock */
return retval;
}
-/* Read the recovery reason. Returns the reason code or -1 if error. */
-int VbGetRecoveryReason(void) {
- int value;
-
- /* Try reading type from BINF.4 */
- value = ReadFileInt(ACPI_BINF_PATH ".4");
- if (-1 != value)
- return value;
-
- /* Fall back to BINF.0 for legacy systems like Mario. */
- switch(ReadFileInt(ACPI_BINF_PATH ".0")) {
- case BINF0_NORMAL:
- case BINF0_DEVELOPER:
- return VBNV_RECOVERY_NOT_REQUESTED;
- case BINF0_RECOVERY_BUTTON:
- return VBNV_RECOVERY_RO_MANUAL;
- case BINF0_RECOVERY_DEV_SCREEN_KEY:
- return VBNV_RECOVERY_RW_DEV_SCREEN;
- case BINF0_RECOVERY_RW_FW_BAD:
- case BINF0_RECOVERY_NO_OS:
- return VBNV_RECOVERY_RW_NO_OS;
- case BINF0_RECOVERY_BAD_OS:
- return VBNV_RECOVERY_RW_INVALID_OS;
- case BINF0_RECOVERY_OS_INITIATED:
- return VBNV_RECOVERY_LEGACY;
- default:
- /* Other values don't map cleanly to firmware type. */
- return -1;
- }
-}
-
-
-/* Read the active main firmware type into the destination buffer.
- * Passed the destination and its size. Returns the destination, or
- * NULL if error. */
-const char* VbReadMainFwType(char* dest, int size) {
-
- /* Try reading type from BINF.3 */
- switch(ReadFileInt(ACPI_BINF_PATH ".3")) {
- case BINF3_RECOVERY:
- return StrCopy(dest, "recovery", size);
- case BINF3_NORMAL:
- return StrCopy(dest, "normal", size);
- case BINF3_DEVELOPER:
- return StrCopy(dest, "developer", size);
- default:
- break; /* Fall through to legacy handling */
- }
-
- /* Fall back to BINF.0 for legacy systems like Mario. */
- switch(ReadFileInt(ACPI_BINF_PATH ".0")) {
- case -1:
- /* Both BINF.0 and BINF.3 are missing, so this isn't Chrome OS
- * firmware. */
- return StrCopy(dest, "nonchrome", size);
- case BINF0_NORMAL:
- return StrCopy(dest, "normal", size);
- case BINF0_DEVELOPER:
- return StrCopy(dest, "developer", size);
- case BINF0_RECOVERY_BUTTON:
- case BINF0_RECOVERY_DEV_SCREEN_KEY:
- case BINF0_RECOVERY_RW_FW_BAD:
- case BINF0_RECOVERY_NO_OS:
- case BINF0_RECOVERY_BAD_OS:
- case BINF0_RECOVERY_OS_INITIATED:
- case BINF0_RECOVERY_TPM_ERROR:
- /* Assorted flavors of recovery boot reason. */
- return StrCopy(dest, "recovery", size);
- default:
- /* Other values don't map cleanly to firmware type. */
- return NULL;
- }
-}
-
-
/* Determine whether OS-level debugging should be allowed. Passed the
* destination and its size. Returns 1 if yes, 0 if no, -1 if error. */
int VbGetCrosDebug(void) {
FILE* f = NULL;
char buf[4096] = "";
- int binf3;
char *t, *saveptr;
- /* Try reading firmware type from BINF.3. */
- binf3 = ReadFileInt(ACPI_BINF_PATH ".3");
- if (BINF3_RECOVERY == binf3)
- return 0; /* Recovery mode never allows debug. */
- else if (BINF3_DEVELOPER == binf3)
- return 1; /* Developer firmware always allows debug. */
+ /* Try reading firmware type. */
+ if (VbGetArchPropertyString("mainfw_type", buf, sizeof(buf))) {
+ if (0 == strcmp(buf, "recovery"))
+ return 0; /* Recovery mode never allows debug. */
+ else if (0 == strcmp(buf, "developer"))
+ return 1; /* Developer firmware always allows debug. */
+ }
/* Normal new firmware, older ChromeOS firmware, or non-Chrome firmware.
* For all these cases, check /proc/cmdline for cros_[no]debug. */
@@ -611,7 +138,7 @@ int VbGetCrosDebug(void) {
/* Normal new firmware or older Chrome OS firmware allows debug if the
* dev switch is on. */
- if (1 == ReadFileBit(ACPI_CHSW_PATH, CHSW_DEV_BOOT))
+ if (1 == VbGetSystemPropertyInt("devsw_boot"))
return 1;
/* All other cases disallow debug. */
@@ -733,13 +260,11 @@ LoadKernelDebugExit:
char* GetVdatString(char* dest, int size, VdatStringField field)
{
- VbSharedDataHeader* sh;
- AcpiBuffer* ab = VbGetBuffer(ACPI_VDAT_PATH);
+ VbSharedDataHeader* sh = VbSharedDataRead();
char* value = dest;
- if (!ab)
- return NULL;
- sh = (VbSharedDataHeader*)ab->buffer;
+ if (!sh)
+ return NULL;
switch (field) {
case VDAT_STRING_TIMERS:
@@ -764,25 +289,22 @@ char* GetVdatString(char* dest, int size, VdatStringField field)
break;
default:
- Free(ab);
- return NULL;
+ value = NULL;
+ break;
}
- Free(ab);
+ Free(sh);
return value;
}
int GetVdatInt(VdatIntField field) {
- VbSharedDataHeader* sh;
- AcpiBuffer* ab = VbGetBuffer(ACPI_VDAT_PATH);
+ VbSharedDataHeader* sh = VbSharedDataRead();
int value = -1;
- if (!ab)
+ if (!sh)
return -1;
- sh = (VbSharedDataHeader*)ab->buffer;
-
switch (field) {
case VDAT_INT_FLAGS:
value = (int)sh->flags;
@@ -801,45 +323,20 @@ int GetVdatInt(VdatIntField field) {
break;
}
- Free(ab);
+ Free(sh);
return value;
}
-/* Read a system property integer.
- *
- * Returns the property value, or -1 if error. */
int VbGetSystemPropertyInt(const char* name) {
int value = -1;
- /* Switch positions */
- if (!strcasecmp(name,"devsw_cur")) {
- value = ReadGpio(GPIO_SIGNAL_TYPE_DEV);
- } else if (!strcasecmp(name,"devsw_boot")) {
- value = ReadFileBit(ACPI_CHSW_PATH, CHSW_DEV_BOOT);
- } else if (!strcasecmp(name,"recoverysw_cur")) {
- value = ReadGpio(GPIO_SIGNAL_TYPE_RECOVERY);
- } else if (!strcasecmp(name,"recoverysw_boot")) {
- value = ReadFileBit(ACPI_CHSW_PATH, CHSW_RECOVERY_BOOT);
- } else if (!strcasecmp(name,"recoverysw_ec_boot")) {
- value = ReadFileBit(ACPI_CHSW_PATH, CHSW_RECOVERY_EC_BOOT);
- } else if (!strcasecmp(name,"wpsw_cur")) {
- value = ReadGpio(GPIO_SIGNAL_TYPE_WP);
- if (-1 != value && FwidStartsWith("Mario."))
- value = 1 - value; /* Mario reports this backwards */
- } else if (!strcasecmp(name,"wpsw_boot")) {
- value = ReadFileBit(ACPI_CHSW_PATH, CHSW_WP_BOOT);
- if (-1 != value && FwidStartsWith("Mario."))
- value = 1 - value; /* Mario reports this backwards */
- }
- /* Saved memory is at a fixed location for all H2C BIOS. If the CHSW
- * path exists in sysfs, it's a H2C BIOS. */
- else if (!strcasecmp(name,"savedmem_base")) {
- return (-1 == ReadFileInt(ACPI_CHSW_PATH) ? -1 : 0x00F00000);
- } else if (!strcasecmp(name,"savedmem_size")) {
- return (-1 == ReadFileInt(ACPI_CHSW_PATH) ? -1 : 0x00100000);
- }
- /* NV storage values with no defaults for older BIOS. */
+ /* Check architecture-dependent properties first */
+ value = VbGetArchPropertyInt(name);
+ if (-1 != value)
+ return value;
+
+ /* NV storage values */
else if (!strcasecmp(name,"kern_nv")) {
value = VbGetNvStorage(VBNV_KERNEL_FIELD);
} else if (!strcasecmp(name,"nvram_cleared")) {
@@ -848,28 +345,15 @@ int VbGetSystemPropertyInt(const char* name) {
value = VbGetNvStorage(VBNV_TEST_ERROR_FUNC);
} else if (!strcasecmp(name,"vbtest_errno")) {
value = VbGetNvStorage(VBNV_TEST_ERROR_NUM);
- }
- /* NV storage values. If unable to get from NV storage, fall back to the
- * CMOS reboot field used by older BIOS. */
- else if (!strcasecmp(name,"recovery_request")) {
+ } else if (!strcasecmp(name,"recovery_request")) {
value = VbGetNvStorage(VBNV_RECOVERY_REQUEST);
- if (-1 == value)
- value = VbGetCmosRebootField(CMOSRF_RECOVERY);
} else if (!strcasecmp(name,"dbg_reset")) {
value = VbGetNvStorage(VBNV_DEBUG_RESET_MODE);
- if (-1 == value)
- value = VbGetCmosRebootField(CMOSRF_DEBUG_RESET);
} else if (!strcasecmp(name,"fwb_tries")) {
value = VbGetNvStorage(VBNV_TRY_B_COUNT);
- if (-1 == value)
- value = VbGetCmosRebootField(CMOSRF_TRY_B);
}
/* Other parameters */
- else if (!strcasecmp(name,"recovery_reason")) {
- return VbGetRecoveryReason();
- } else if (!strcasecmp(name,"fmap_base")) {
- value = ReadFileInt(ACPI_FMAP_PATH);
- } else if (!strcasecmp(name,"cros_debug")) {
+ else if (!strcasecmp(name,"cros_debug")) {
value = VbGetCrosDebug();
} else if (!strcasecmp(name,"vdat_flags")) {
value = GetVdatInt(VDAT_INT_FLAGS);
@@ -884,41 +368,13 @@ int VbGetSystemPropertyInt(const char* name) {
return value;
}
-/* Read a system property string into a destination buffer of the specified
- * size.
- *
- * Returns the passed buffer, or NULL if error. */
+
const char* VbGetSystemPropertyString(const char* name, char* dest, int size) {
+ /* Check architecture-dependent properties first */
+ if (VbGetArchPropertyString(name, dest, size))
+ return dest;
- if (!strcasecmp(name,"hwid")) {
- return ReadFileString(dest, size, ACPI_BASE_PATH "/HWID");
- } else if (!strcasecmp(name,"fwid")) {
- return ReadFileString(dest, size, ACPI_BASE_PATH "/FWID");
- } else if (!strcasecmp(name,"ro_fwid")) {
- return ReadFileString(dest, size, ACPI_BASE_PATH "/FRID");
- } else if (!strcasecmp(name,"mainfw_act")) {
- switch(ReadFileInt(ACPI_BINF_PATH ".1")) {
- case 0:
- return StrCopy(dest, "recovery", size);
- case 1:
- return StrCopy(dest, "A", size);
- case 2:
- return StrCopy(dest, "B", size);
- default:
- return NULL;
- }
- } else if (!strcasecmp(name,"mainfw_type")) {
- return VbReadMainFwType(dest, size);
- } else if (!strcasecmp(name,"ecfw_act")) {
- switch(ReadFileInt(ACPI_BINF_PATH ".2")) {
- case 0:
- return StrCopy(dest, "RO", size);
- case 1:
- return StrCopy(dest, "RW", size);
- default:
- return NULL;
- }
- } else if (!strcasecmp(name,"kernkey_vfy")) {
+ if (!strcasecmp(name,"kernkey_vfy")) {
switch(GetVdatInt(VDAT_INT_KERNEL_KEY_VERIFIED)) {
case 0:
return "hash";
@@ -933,17 +389,18 @@ const char* VbGetSystemPropertyString(const char* name, char* dest, int size) {
return GetVdatString(dest, size, VDAT_STRING_LOAD_FIRMWARE_DEBUG);
} else if (!strcasecmp(name, "vdat_lkdebug")) {
return GetVdatString(dest, size, VDAT_STRING_LOAD_KERNEL_DEBUG);
- } else
- return NULL;
+ }
+
+ return NULL;
}
-/* Set a system property integer.
- *
- * Returns 0 if success, -1 if error. */
int VbSetSystemPropertyInt(const char* name, int value) {
+ /* Check architecture-dependent properties first */
+ if (0 == VbSetArchPropertyInt(name, value))
+ return 0;
- /* NV storage values with no defaults for older BIOS. */
+ /* NV storage values */
if (!strcasecmp(name,"nvram_cleared")) {
/* Can only clear this flag; it's set inside the NV storage library. */
return VbSetNvStorage(VBNV_KERNEL_SETTINGS_RESET, 0);
@@ -953,32 +410,19 @@ int VbSetSystemPropertyInt(const char* name, int value) {
return VbSetNvStorage(VBNV_TEST_ERROR_FUNC, value);
} else if (!strcasecmp(name,"vbtest_errno")) {
return VbSetNvStorage(VBNV_TEST_ERROR_NUM, value);
- }
- /* NV storage values. If unable to get from NV storage, fall back to the
- * CMOS reboot field used by older BIOS. */
- else if (!strcasecmp(name,"recovery_request")) {
- if (0 == VbSetNvStorage(VBNV_RECOVERY_REQUEST, value))
- return 0;
- return VbSetCmosRebootField(CMOSRF_RECOVERY, value);
+ } else if (!strcasecmp(name,"recovery_request")) {
+ return VbSetNvStorage(VBNV_RECOVERY_REQUEST, value);
} else if (!strcasecmp(name,"dbg_reset")) {
- if (0 == VbSetNvStorage(VBNV_DEBUG_RESET_MODE, value))
- return 0;
- return VbSetCmosRebootField(CMOSRF_DEBUG_RESET, value);
+ return VbSetNvStorage(VBNV_DEBUG_RESET_MODE, value);
} else if (!strcasecmp(name,"fwb_tries")) {
- if (0 == VbSetNvStorage(VBNV_TRY_B_COUNT, value))
- return 0;
- return VbSetCmosRebootField(CMOSRF_TRY_B, value);
+ return VbSetNvStorage(VBNV_TRY_B_COUNT, value);
}
return -1;
}
-/* Set a system property string.
- *
- * Returns 0 if success, -1 if error. */
int VbSetSystemPropertyString(const char* name, const char* value) {
-
- /* TODO: support setting */
- return -1;
+ /* Chain to architecture-dependent properties */
+ return VbSetArchPropertyString(name, value);
}
diff --git a/host/lib/host_misc.c b/host/lib/host_misc.c
index 91eaea25..f8dd9b8f 100644
--- a/host/lib/host_misc.c
+++ b/host/lib/host_misc.c
@@ -9,6 +9,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include "host_common.h"
@@ -18,6 +19,13 @@
#include "vboot_common.h"
+char* StrCopy(char* dest, const char* src, int dest_size) {
+ strncpy(dest, src, dest_size);
+ dest[dest_size - 1] = '\0';
+ return dest;
+}
+
+
uint8_t* ReadFile(const char* filename, uint64_t* size) {
FILE* f;
uint8_t* buf;
@@ -50,6 +58,45 @@ uint8_t* ReadFile(const char* filename, uint64_t* size) {
}
+char* ReadFileString(char* dest, int size, const char* filename) {
+ char* got;
+ FILE* f;
+
+ f = fopen(filename, "rt");
+ if (!f)
+ return NULL;
+
+ got = fgets(dest, size, f);
+ fclose(f);
+ return got;
+}
+
+
+int ReadFileInt(const char* filename) {
+ char buf[64];
+ int value;
+ char* e = NULL;
+
+ if (!ReadFileString(buf, sizeof(buf), filename))
+ return -1;
+
+ /* Convert to integer. Allow characters after the int ("123 blah"). */
+ value = strtol(buf, &e, 0);
+ if (e == buf)
+ return -1; /* No characters consumed, so conversion failed */
+
+ return value;
+}
+
+
+int ReadFileBit(const char* filename, int bitmask) {
+ int value = ReadFileInt(filename);
+ if (value == -1)
+ return -1;
+ else return (value & bitmask ? 1 : 0);
+}
+
+
int WriteFile(const char* filename, const void *data, uint64_t size) {
FILE *f = fopen(filename, "wb");
if (!f) {
diff --git a/utility/crossystem_main.c b/utility/crossystem_main.c
index 31634381..133ab007 100644
--- a/utility/crossystem_main.c
+++ b/utility/crossystem_main.c
@@ -47,6 +47,7 @@ const Param sys_param_list[] = {
{"tpm_fwver", 0, "Firmware version stored in TPM", "0x%08x"},
{"tpm_kernver", 0, "Kernel version stored in TPM", "0x%08x"},
/* Read-only strings */
+ {"arch", IS_STRING, "Platform architecture"},
{"hwid", IS_STRING, "Hardware ID"},
{"fwid", IS_STRING, "Active firmware ID"},
{"ro_fwid", IS_STRING, "Read-only firmware ID"},