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>
diff --git a/Makefile b/Makefile
index d12639d..f1c4b60 100644
--- a/Makefile
+++ b/Makefile
@@ -20,6 +20,11 @@
 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 3226ac3..7c2866b 100644
--- a/host/Makefile
+++ b/host/Makefile
@@ -8,12 +8,14 @@
 
 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 0000000..08ae723
--- /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 0000000..4304ce7
--- /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 0000000..b8e6add
--- /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 0000000..ee8425b
--- /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 cbf9eaf..22b3141 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 5c5dec0..2e29d04 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 @@
 } 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 @@
 }
 
 
-/* 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)
+
+  if (0 != VbReadNvStorage(&vnc))
     return -1;
-
-  if (0 != fseek(f, offs, SEEK_SET) ||
-      1 != fread(vnc.raw, VBNV_BLOCK_SIZE, 1, f)) {
-    fclose(f);
-    return -1;
-  }
-
-  fclose(f);
-
   if (0 != VbNvSetup(&vnc))
     return -1;
   retval = VbNvGet(&vnc, param, &value);
@@ -453,32 +76,13 @@
 }
 
 
-/* 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 @@
     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 @@
   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 @@
 
   /* 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 @@
 
 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 @@
       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 @@
       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 @@
     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 @@
   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) {
 
-  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")) {
+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,"kernkey_vfy")) {
     switch(GetVdatInt(VDAT_INT_KERNEL_KEY_VERIFIED)) {
       case 0:
         return "hash";
@@ -933,17 +389,18 @@
     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 @@
     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 91eaea2..f8dd9b8 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 @@
 }
 
 
+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 3163438..133ab00 100644
--- a/utility/crossystem_main.c
+++ b/utility/crossystem_main.c
@@ -47,6 +47,7 @@
   {"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"},