summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2011-04-07 10:02:00 -0700
committerRandall Spangler <rspangler@chromium.org>2011-04-07 10:02:00 -0700
commiteb59195473246f8ff3076950f3c3b8d3564d433d (patch)
treebdb23c2b5d57060d5517c041df1373a360818980
parent9522b84029e48579303e9dbc287266eae93e0af9 (diff)
downloadvboot-eb59195473246f8ff3076950f3c3b8d3564d433d.tar.gz
Refactor crossystem to move x86-specific implementation to its own file.
This should be ready for the ARM team to pick up and work on. I added a placeholder ARM implementation file, though it's not hooked up in the Makefile yet. As soon as you implement the VbNvStorage APIs, all the related crossystem commands will start working. Ditto for VbSharedData. The params which x86 gets from ACPI you'll need to get from u-boot somehow, probably via your own kernel driver. R=robotboy@chromium.org BUG=chromium-os:12522 TEST=emerge-x86-alex vboot_reference, make sure it still works on x86 Review URL: http://codereview.chromium.org/6780008 Change-Id: I628ee56508421b937ed50db7cb9b8385408d2f5e
-rw-r--r--host/Makefile2
-rw-r--r--host/arch/arm/lib/crossystem_arch.c106
-rw-r--r--host/arch/x86/lib/crossystem_arch.c591
-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
7 files changed, 893 insertions, 604 deletions
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/arm/lib/crossystem_arch.c b/host/arch/arm/lib/crossystem_arch.c
new file mode 100644
index 00000000..34f38f6e
--- /dev/null
+++ b/host/arch/arm/lib/crossystem_arch.c
@@ -0,0 +1,106 @@
+/* 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,"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..1e1f75b8
--- /dev/null
+++ b/host/arch/x86/lib/crossystem_arch.c
@@ -0,0 +1,591 @@
+/* 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,"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) {