summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2011-05-02 16:23:30 -0700
committerVadim Bendebury <vbendeb@chromium.org>2011-05-05 14:42:09 -0700
commitc3574086a82d04b3584712f7e15a8eb4ea6d40a0 (patch)
tree9cd5767794a0394c79a4dacdb7fbbc6d08ae3a50
parent1fb83158560de5eaec4f04d021afe0594e03cc5d (diff)
downloadvboot-c3574086a82d04b3584712f7e15a8eb4ea6d40a0.tar.gz
Introduce arm support in crossystem.
This CL builds upon earlier firmware and kernel changes (see CLs related to the same bug, chromium-os:12522). ARM firmware now simulates both Nvram storage and VDAT buffer, the structures the x86 version uses extensively to communicate back and forth between firmware/kernel/userland. So, to make crossystem work on arm, all what's needed is to provide architecture specific interface to Nvram and VDAT simulation, and architecture specific processing for variables which are accessed on ARM platforms in a different way. The few discrepancies and platform specifics which had to be addressed for ARM specifically are as follows: - the Nvram contents are cached in the shared memory and available for reading as part of /sys/kernel/debug/chromeos_arm. When writing Nvram, the same file needs to be written, but only the 16 bytes (representing the Nvram contents) are aacepted. - the VDAT buffer also comes from the shared memory (as part of the same sysfs file) - when crossystem starts, it needs to read in this shared memory contents, a` weak' function VbArchInit() is being added such that it is provided on ARM platforms only, on x86 an empty stub is called. - current developer/recovery request/ro firmware switch states are retrieved through GPIO drivers. The GPIO numbers are defined in the file, the GPIO driver is supposed to be configured before crsossystem can operate. - the BINF values are supplied through an array within shared memory, it would be easy to refactor both x86 and ARM use the same code to process BINF values, but with this submission the code is duplicated to minimize x86 impact. - the following crossystem variables do not have ARM equivalents, thier values are reported as '(error)': recoverysw_ec_boot savedmem_base savedmem_size BUG=chromium-os:12522 TEST=manual: . bring up a kaen system . execute the following script to enable the appropriate GPIOSs: for gpio in 56 59 168; do echo $gpio > /sys/class/gpio/export; done . run `crossystem' and observe reasonable output values . to verify that it reads GPIOs properly, try echo $(./crossystem recoverysw_cur) with the miniservo 'GOOG_REC' button pressed and released, observe different readings (note that the state of the button is reversed, the released button is reported as '1') . to verify the write capabilities, note that the nvram contents can be accessed using the following shell commands echo 3 > /proc/sys/vm/drop_caches 2>/dev/null dd if=/dev/mmcblk0 of=/tmp/blk bs=16 count=1 && \ od -t x1 /tmp/blk | head -1 (the first command cause the device cache dropped, and the second command accesses the device contents. vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv localhost var # echo $(./crossystem fwb_tries) 10 localhost var # echo 3 > /proc/sys/vm/drop_caches localhost var # 2>/dev/null dd if=/dev/mmcblk0 of=/tmp/blk bs=16 count=1 && od -t x1 /tmp/blk | head -1 0000000 60 0a 00 be 00 00 00 00 00 00 00 02 00 00 00 a2 localhost var # ./crossystem fwb_tries=9 localhost var # echo $(./crossystem fwb_tries) 9 localhost var # echo 3 > /proc/sys/vm/drop_caches localhost var # 2>/dev/null dd if=/dev/mmcblk0 of=/tmp/blk bs=16 count=1 && od -t x1 /tmp/blk | head -1 0000000 60 09 00 be 00 00 00 00 00 00 00 02 00 00 00 8a localhost var # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Change-Id: Ie4c6ff44441d98a42b1057953208fdb90c08f46d Reviewed-on: http://gerrit.chromium.org/gerrit/113 Reviewed-by: Randall Spangler <rspangler@chromium.org> Tested-by: Vadim Bendebury <vbendeb@chromium.org>
-rw-r--r--firmware/lib/include/vboot_common.h2
-rw-r--r--host/arch/arm/lib/crossystem_arch.c294
-rw-r--r--host/arch/x86/lib/crossystem_arch.c4
-rw-r--r--host/include/crossystem_arch.h8
-rw-r--r--utility/crossystem_main.c10
5 files changed, 254 insertions, 64 deletions
diff --git a/firmware/lib/include/vboot_common.h b/firmware/lib/include/vboot_common.h
index ea172af3..88bf9ac6 100644
--- a/firmware/lib/include/vboot_common.h
+++ b/firmware/lib/include/vboot_common.h
@@ -11,6 +11,8 @@
#include "cryptolib.h"
#include "vboot_struct.h"
+#define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0]))
+
/* Error Codes for all common functions. */
enum {
VBOOT_SUCCESS = 0,
diff --git a/host/arch/arm/lib/crossystem_arch.c b/host/arch/arm/lib/crossystem_arch.c
index 4304ce7c..6d62e7c3 100644
--- a/host/arch/arm/lib/crossystem_arch.c
+++ b/host/arch/arm/lib/crossystem_arch.c
@@ -6,103 +6,277 @@
#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"
+#include "host_common.h"
+#include "crossystem_arch.h"
+#define CONFIG_LENGTH_FMAP 0x400
-int VbReadNvStorage(VbNvContext* vnc) {
- /* TODO: IMPLEMENT ME! */
- return -1;
+#define offsetof(struct_name, field) ((int) &(((struct_name*)0)->field))
+
+/* This is used to keep u-boot and kernel in sync */
+#define SHARED_MEM_VERSION 1
+#define SHARED_MEM_SIGNATURE "CHROMEOS"
+
+typedef struct {
+ const char *signal_name;
+ unsigned gpio_number;
+} GpioMap;
+
+static const GpioMap vb_gpio_map_kaen[] = {
+ {"recoverysw_cur", 56},
+ {"devsw_cur", 168},
+ {"wpsw_cur", 59},
+};
+
+/* This is map is for kaen, function to gpio number mapping */
+
+/*
+ * This structure has been copied from u-boot-next
+ * files/lib/chromeos/os_storage.c. Keep it in sync until a better interface
+ * is implemented.
+ */
+typedef struct {
+ uint32_t total_size;
+ uint8_t signature[10];
+ uint16_t version;
+ uint64_t nvcxt_lba;
+ uint16_t vbnv[2];
+ uint8_t nvcxt_cache[VBNV_BLOCK_SIZE];
+ uint8_t write_protect_sw;
+ uint8_t recovery_sw;
+ uint8_t developer_sw;
+ uint8_t binf[5];
+ uint32_t chsw;
+ uint8_t hwid[256];
+ uint8_t fwid[256];
+ uint8_t frid[256];
+ uint32_t fmap_base;
+ uint8_t shared_data_body[CONFIG_LENGTH_FMAP];
+} __attribute__((packed)) VbSharedMem;
+
+typedef struct {
+ const char *cs_field_name;
+ const void *cs_value;
+} VbVarInfo;
+
+static VbSharedMem shared_memory;
+static const char *blob_name = "/sys/kernel/debug/chromeos_arm";
+static VbVarInfo vb_cs_map[] = {
+ {"hwid", &shared_memory.hwid},
+ {"fwid", &shared_memory.fwid},
+ {"ro_fwid", &shared_memory.frid},
+ {"devsw_boot", &shared_memory.developer_sw},
+ {"recoverysw_boot", &shared_memory.recovery_sw},
+ {"wpsw_boot", &shared_memory.write_protect_sw},
+ {"recovery_reason", &shared_memory.binf[4]},
+};
+
+static int VbGetGpioStatus(unsigned gpio_number) {
+ char const *gpio_name_format = "/sys/class/gpio/gpio%d/value";
+ char gpio_name [80];
+ char gpio_value[3]; /* gpio value file contains the value and the CR */
+ FILE *gpio_file;
+ int rv = -1, size;
+
+ snprintf(gpio_name, sizeof(gpio_name), gpio_name_format, gpio_number);
+ gpio_file = fopen(gpio_name, "r");
+ if (!gpio_file) {
+ fprintf(stderr, "%s: failed to open %s\n", __FUNCTION__, gpio_name);
+ return -1;
+ }
+
+ size = fread(&gpio_value, 1, sizeof(gpio_value), gpio_file);
+ if ((size == 2) && (gpio_value[1] == 0xa)) {
+ rv = gpio_value[0] - '0'; /* we expect 0 or 1 only */
+ } else {
+ fprintf(stderr, "%s: failed to read %s, got %d\n",
+ __FUNCTION__, gpio_name, size);
+ }
+ fclose(gpio_file);
+ return rv;
}
+static int VbGetVarGpio(const char* name) {
+ int i;
-int VbWriteNvStorage(VbNvContext* vnc) {
- /* TODO: IMPLEMENT ME! */
- return -1;
+ for (i = 0; i < ARRAY_SIZE(vb_gpio_map_kaen); i++) {
+ if (!strcmp(name, vb_gpio_map_kaen[i].signal_name))
+ return VbGetGpioStatus(vb_gpio_map_kaen[i].gpio_number);
+ }
+ return 2; /* means not found */
}
+static int VbReadSharedMemory(void) {
+ FILE *data_file = NULL;
+ int rv = -1;
+ int size;
+
+ do {
+ data_file = fopen(blob_name, "rb");
+ if (!data_file) {
+ fprintf(stderr, "%s: failed to open %s\n", __FUNCTION__, blob_name);
+ break;
+ }
+ size = fread(&shared_memory, 1, sizeof(shared_memory), data_file);
+ if ((size != sizeof(shared_memory)) || (size != shared_memory.total_size)) {
+ fprintf(stderr, "%s: failed to read shared memory: got %d bytes, "
+ "expected %d, should have been %d\n",
+ __FUNCTION__,
+ size,
+ sizeof(shared_memory),
+ shared_memory.total_size);
+ break;
+ }
+
+ if (strcmp((const char*)shared_memory.signature, SHARED_MEM_SIGNATURE)) {
+ fprintf(stderr, "%s: signature verification failed\n", __FUNCTION__);
+ break;
+ }
-VbSharedDataHeader* VbSharedDataRead(void) {
- /* TODO: IMPLEMENT ME! */
+ if (shared_memory.version != SHARED_MEM_VERSION) {
+ fprintf(stderr, "%s: version mismatch: %d != %d\n",
+ __FUNCTION__, shared_memory.version, SHARED_MEM_VERSION);
+ break;
+ }
+ rv = 0;
+ } while (0);
+
+ if (data_file)
+ fclose(data_file);
+
+ return rv;
+}
+
+/* Retrieve the address of an entity in the shared memory based on the entity
+ * name, as described in vb_cs_map table.
+ *
+ * Return NULL if the entity name is not found in the table.
+ */
+static const void* VbGetVarAuto(const char* name) {
+ int i;
+ VbVarInfo *pi;
+
+ for (i = 0, pi = vb_cs_map; i < ARRAY_SIZE(vb_cs_map); i++, pi++) {
+ if (strcmp(pi->cs_field_name, name)) continue;
+ return pi->cs_value;
+ }
return NULL;
}
+int VbReadNvStorage(VbNvContext* vnc) {
+ Memcpy(vnc->raw, shared_memory.nvcxt_cache, sizeof(vnc->raw));
+ return 0;
+}
+
+int VbWriteNvStorage(VbNvContext* vnc) {
+ FILE *data_file = NULL;
+ int rv = -1;
+ int size;
+
+ do {
+ data_file = fopen(blob_name, "w");
+ if (!data_file) {
+ fprintf(stderr, "%s: failed to open %s\n", __FUNCTION__, blob_name);
+ break;
+ }
+ size = fwrite(vnc->raw, 1, sizeof(vnc->raw), data_file);
+ if (size != sizeof(vnc->raw)) {
+ fprintf(stderr, "%s: failed to write shared memory (%d)\n",
+ __FUNCTION__, size);
+ break;
+ }
+ rv = 0;
+ } while (0);
+
+ if (data_file)
+ fclose(data_file);
+
+ return rv;
+}
+
+VbSharedDataHeader *VbSharedDataRead(void) {
+ /* don't need this malloc/copy, but have to do it to comply with the
+ * wrapper.
+ */
+ VbSharedDataHeader *p = Malloc(sizeof(*p));
+ Memcpy(p, shared_memory.shared_data_body, sizeof(*p));
+ return p;
+}
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;
- }
+ const uint8_t *value;
+ int rv;
+
+ value = VbGetVarAuto(name);
- /* 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")) {
+ if (value) return (int) *value;
+
+ rv = VbGetVarGpio(name);
+ if (rv <= 1) return rv;
+
+ if (!strcasecmp(name,"fmap_base")) {
+ return shared_memory.fmap_base;
}
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. */
+ const char* value = VbGetVarAuto(name);
+ if (value) return StrCopy(dest, value, size);
+
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);
+ switch(shared_memory.binf[2]) {
+ 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 StrCopy(dest, "developer", size);
+ switch(shared_memory.binf[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:
+ return NULL;
+ }
} else if (!strcasecmp(name,"ecfw_act")) {
- return StrCopy(dest, "RO", size);
+ switch(shared_memory.binf[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) {
- /* TODO: IMPLEMENT ME! */
+ /* All is handled in arch independent fashion */
return -1;
}
-
int VbSetArchPropertyString(const char* name, const char* value) {
- /* If there were settable architecture-dependent string properties,
- * they'd be here. */
+ /* All is handled in arch independent fashion */
return -1;
}
+
+int VbArchInit(void)
+{
+ return VbReadSharedMemory();
+}
diff --git a/host/arch/x86/lib/crossystem_arch.c b/host/arch/x86/lib/crossystem_arch.c
index 9f766949..8b320e4b 100644
--- a/host/arch/x86/lib/crossystem_arch.c
+++ b/host/arch/x86/lib/crossystem_arch.c
@@ -48,10 +48,6 @@
#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
diff --git a/host/include/crossystem_arch.h b/host/include/crossystem_arch.h
index ee8425b4..6d33c65b 100644
--- a/host/include/crossystem_arch.h
+++ b/host/include/crossystem_arch.h
@@ -11,6 +11,14 @@
#include "vboot_nvstorage.h"
#include "vboot_struct.h"
+/* Firmware types from BINF.3. Placed in the common file because both x86 and
+ * arm use this. The constants are defined in "Chrome OS Main Processor
+ * Firmware Spec"
+ */
+#define BINF3_RECOVERY 0
+#define BINF3_NORMAL 1
+#define BINF3_DEVELOPER 2
+
/* INTERNAL APIS FOR CROSSYSTEM AVAILABLE TO ARCH-SPECIFIC FUNCTIONS */
diff --git a/utility/crossystem_main.c b/utility/crossystem_main.c
index 14b7e226..6b249e00 100644
--- a/utility/crossystem_main.c
+++ b/utility/crossystem_main.c
@@ -14,6 +14,11 @@
/* Max length of a string parameter */
#define MAX_STRING 8192
+/*
+ * Call arch specific init, if provided, otherwise use the 'weak' stub.
+ */
+int __VbArchInit(void) { return 0; }
+int VbArchInit(void) __attribute__((weak, alias("__VbArchInit")));
/* Flags for Param */
#define IS_STRING 0x01 /* String (not present = integer) */
#define CAN_WRITE 0x02 /* Writable (not present = read-only */
@@ -212,6 +217,11 @@ int main(int argc, char* argv[]) {
else
progname = argv[0];
+ if (VbArchInit()) {
+ fprintf(stderr, "Failed to initialize\n");
+ return -1;
+ }
+
/* If no args specified, print all params */
if (argc == 1)
return PrintAllParams(0);