diff options
author | Randall Spangler <rspangler@chromium.org> | 2014-06-24 15:31:04 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-06-28 00:56:17 +0000 |
commit | 9e1da784487fb8cfbe4e76693e07205b66675bda (patch) | |
tree | 9beada3e8c3667c27765702708b537aaa76d5062 | |
parent | d11086caf05c692815ae6f90aa83a4fc30d50ed7 (diff) | |
download | vboot-9e1da784487fb8cfbe4e76693e07205b66675bda.tar.gz |
Add nvstorage / crossystem support for new vboot2 fields
This allows testing vboot2. These fields are ignored by original
vboot firmware.
BUG=chromium:370082
BRANCH=none
TEST=manual
crossystem -> fw_tried=A, fw_result=unknown, fw_try_next=A
crossystem fw_tried=B
echo $? -> 1
crossystem -> fw_tried=A, fw_result=unknown, fw_try_next=A
crossystem fw_try_next=B
crossystem -> fw_tried=A, fw_result=unknown, fw_try_next=B
crossystem fw_try_next=beats_me
echo $? -> 1
crossystem -> fw_tried=A, fw_result=unknown, fw_try_next=B
crossystem fw_try_next=A
crossystem -> fw_tried=A, fw_result=unknown, fw_try_next=A
crossystem fw_result=trying
crossystem -> fw_tried=A, fw_result=trying, fw_try_next=A
crossystem fw_result=bupkis
echo $? -> 1
crossystem -> fw_tried=A, fw_result=trying, fw_try_next=A
crossystem fw_result=success
crossystem -> fw_tried=A, fw_result=success, fw_try_next=A
crossystem fw_result=failure
crossystem -> fw_tried=A, fw_result=failure, fw_try_next=A
crossystem fw_result=unknown
crossystem -> fw_tried=A, fw_result=unknown, fw_try_next=A
crossystem -> fw_try_count = 0, fwb_tries = 0
crossystem fw_try_count=6
crossystem -> fw_try_count = 6, fwb_tries = 6
crossystem fwb_tries=0
crossystem -> fw_try_count = 0, fwb_tries = 0
Change-Id: I1532f3384f8c05de2a7ff3f35abcc35d18049491
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/205475
-rw-r--r-- | firmware/2lib/2nvstorage.c | 5 | ||||
-rw-r--r-- | firmware/include/vboot_nvstorage.h | 31 | ||||
-rw-r--r-- | firmware/lib/vboot_nvstorage.c | 45 | ||||
-rw-r--r-- | host/lib/crossystem.c | 38 | ||||
-rw-r--r-- | tests/vboot_nvstorage_test.c | 36 | ||||
-rw-r--r-- | utility/crossystem.c | 6 |
6 files changed, 150 insertions, 11 deletions
diff --git a/firmware/2lib/2nvstorage.c b/firmware/2lib/2nvstorage.c index 067f0aef..02904741 100644 --- a/firmware/2lib/2nvstorage.c +++ b/firmware/2lib/2nvstorage.c @@ -15,6 +15,11 @@ * Constants for NV storage. We use this rather than structs and bitfields so * the data format is consistent across platforms and compilers. Total NV * storage size is VB2_NVDATA_SIZE = 16 bytes. + * + * These constants must match the equivalent constants in + * lib/vboot_nvstorage.c. (We currently don't share a common header file + * because we're tring to keep the two libs independent, and we hope to + * deprecate that one.) */ enum vb2_nv_offset { diff --git a/firmware/include/vboot_nvstorage.h b/firmware/include/vboot_nvstorage.h index 534fb7e4..0a9a4841 100644 --- a/firmware/include/vboot_nvstorage.h +++ b/firmware/include/vboot_nvstorage.h @@ -45,8 +45,14 @@ typedef enum VbNvParam { /* * Number of times to try booting RW firmware slot B before slot A. * Valid range: 0-15. + * + * Vboot2: Number of times to try the firmware in VBNV_FW_TRY_NEXT. + * + * These refer to the same field, but have different enum values so + * case statement don't complain about duplicates. */ VBNV_TRY_B_COUNT, + VBNV_FW_TRY_COUNT, /* * Request recovery mode on next boot; see VBNB_RECOVERY_* below for * currently defined reason codes. 8-bit value. @@ -85,8 +91,33 @@ typedef enum VbNvParam { VBNV_RECOVERY_SUBCODE, /* Request that NVRAM be backed up at next boot if possible. */ VBNV_BACKUP_NVRAM_REQUEST, + + /* Vboot2: Firmware slot to try next. 0=A, 1=B */ + VBNV_FW_TRY_NEXT, + /* Vboot2: Firmware slot tried this boot (0=A, 1=B) */ + VBNV_FW_TRIED, + /* Vboot2: Result of trying that firmware (see vb2_fw_result) */ + VBNV_FW_RESULT, + + } VbNvParam; +/* Result of trying the firmware in VBNV_FW_TRIED */ +typedef enum VbFwResult { + /* Unknown */ + VBNV_FW_RESULT_UNKNOWN = 0, + + /* Trying a new slot, but haven't reached success/failure */ + VBNV_FW_RESULT_TRYING = 1, + + /* Successfully booted to the OS */ + VBNV_FW_RESULT_SUCCESS = 2, + + /* Known failure */ + VBNV_FW_RESULT_FAILURE = 3, + +} VbFwResult; + /* Recovery reason codes for VBNV_RECOVERY_REQUEST */ /* Recovery not requested. */ #define VBNV_RECOVERY_NOT_REQUESTED 0x00 diff --git a/firmware/lib/vboot_nvstorage.c b/firmware/lib/vboot_nvstorage.c index 258e5aff..3c5d1e27 100644 --- a/firmware/lib/vboot_nvstorage.c +++ b/firmware/lib/vboot_nvstorage.c @@ -17,6 +17,10 @@ /* * Constants for NV storage. We use this rather than structs and bitfields so * the data format is consistent across platforms and compilers. + * + * These constants must match the equivalent constants in 2lib/2nvstorage.c. + * (We currently don't share a common header file because we're tring to keep + * the two libs independent, and we hope to deprecate this one.) */ #define HEADER_OFFSET 0 #define HEADER_MASK 0xC0 @@ -45,6 +49,11 @@ #define RECOVERY_SUBCODE_OFFSET 6 +#define BOOT2_OFFSET 7 +#define BOOT2_RESULT_MASK 0x03 +#define BOOT2_TRIED 0x04 +#define BOOT2_TRY_NEXT 0x08 + #define KERNEL_FIELD_OFFSET 11 #define CRC_OFFSET 15 @@ -103,6 +112,7 @@ int VbNvGet(VbNvContext *context, VbNvParam param, uint32_t *dest) return 0; case VBNV_TRY_B_COUNT: + case VBNV_FW_TRY_COUNT: *dest = raw[BOOT_OFFSET] & BOOT_TRY_B_COUNT_MASK; return 0; @@ -159,6 +169,18 @@ int VbNvGet(VbNvContext *context, VbNvParam param, uint32_t *dest) *dest = (raw[BOOT_OFFSET] & BOOT_BACKUP_NVRAM ? 1 : 0); return 0; + case VBNV_FW_TRY_NEXT: + *dest = (raw[BOOT2_OFFSET] & BOOT2_TRY_NEXT ? 1 : 0); + return 0; + + case VBNV_FW_TRIED: + *dest = (raw[BOOT2_OFFSET] & BOOT2_TRIED ? 1 : 0); + return 0; + + case VBNV_FW_RESULT: + *dest = raw[BOOT2_OFFSET] & BOOT2_RESULT_MASK; + return 0; + default: return 1; } @@ -196,6 +218,7 @@ int VbNvSet(VbNvContext *context, VbNvParam param, uint32_t value) break; case VBNV_TRY_B_COUNT: + case VBNV_FW_TRY_COUNT: /* Clip to valid range. */ if (value > BOOT_TRY_B_COUNT_MASK) value = BOOT_TRY_B_COUNT_MASK; @@ -289,6 +312,28 @@ int VbNvSet(VbNvContext *context, VbNvParam param, uint32_t value) raw[BOOT_OFFSET] &= ~BOOT_BACKUP_NVRAM; break; + case VBNV_FW_TRY_NEXT: + if (value) + raw[BOOT2_OFFSET] |= BOOT2_TRY_NEXT; + else + raw[BOOT2_OFFSET] &= ~BOOT2_TRY_NEXT; + break; + + case VBNV_FW_TRIED: + if (value) + raw[BOOT2_OFFSET] |= BOOT2_TRIED; + else + raw[BOOT2_OFFSET] &= ~BOOT2_TRIED; + break; + + case VBNV_FW_RESULT: + /* Map out of range values to unknown */ + if (value > BOOT2_RESULT_MASK) + value = VBNV_FW_RESULT_UNKNOWN; + + raw[BOOT2_OFFSET] &= ~BOOT2_RESULT_MASK; + raw[BOOT2_OFFSET] |= (uint8_t)value; + break; default: return 1; diff --git a/host/lib/crossystem.c b/host/lib/crossystem.c index f88d22c6..d6555c67 100644 --- a/host/lib/crossystem.c +++ b/host/lib/crossystem.c @@ -60,6 +60,7 @@ typedef enum VbBuildOption { VB_BUILD_OPTION_NODEBUG } VbBuildOption; +static const char *fw_results[] = {"unknown", "trying", "success", "failure"}; /* Masks for kern_nv usage by kernel. */ #define KERN_NV_FWUPDATE_TRIES_MASK 0x0000000F @@ -464,6 +465,8 @@ int VbGetSystemPropertyInt(const char* name) { value = VbGetNvStorage(VBNV_TRY_B_COUNT); } else if (!strcasecmp(name,"fw_vboot2")) { value = GetVdatInt(VDAT_INT_FW_BOOT2); + } else if (!strcasecmp(name,"fw_try_count")) { + value = VbGetNvStorage(VBNV_FW_TRY_COUNT); } else if (!strcasecmp(name,"fwupdate_tries")) { value = VbGetNvStorage(VBNV_KERNEL_FIELD); if (value != -1) @@ -547,6 +550,16 @@ const char* VbGetSystemPropertyString(const char* name, char* dest, return GetVdatString(dest, size, VDAT_STRING_LOAD_KERNEL_DEBUG); } else if (!strcasecmp(name, "ddr_type")) { return unknown_string; + } else if (!strcasecmp(name, "fw_try_next")) { + return VbGetNvStorage(VBNV_FW_TRY_NEXT) ? "B" : "A"; + } else if (!strcasecmp(name, "fw_tried")) { + return VbGetNvStorage(VBNV_FW_TRIED) ? "B" : "A"; + } else if (!strcasecmp(name, "fw_result")) { + int v = VbGetNvStorage(VBNV_FW_RESULT); + if (v < ARRAY_SIZE(fw_results)) + return fw_results[v]; + else + return "unknown"; } return NULL; @@ -578,6 +591,8 @@ int VbSetSystemPropertyInt(const char* name, int value) { return VbSetNvStorage(VBNV_CLEAR_TPM_OWNER_DONE, 0); } else if (!strcasecmp(name,"fwb_tries")) { return VbSetNvStorage(VBNV_TRY_B_COUNT, value); + } else if (!strcasecmp(name,"fw_try_count")) { + return VbSetNvStorage(VBNV_FW_TRY_COUNT, value); } else if (!strcasecmp(name,"oprom_needed")) { return VbSetNvStorage(VBNV_OPROM_NEEDED, value); } else if (!strcasecmp(name,"backup_nvram_request")) { @@ -614,5 +629,26 @@ int VbSetSystemPropertyInt(const char* name, int value) { int VbSetSystemPropertyString(const char* name, const char* value) { /* Chain to architecture-dependent properties */ - return VbSetArchPropertyString(name, value); + if (0 == VbSetArchPropertyString(name, value)) + return 0; + + if (!strcasecmp(name, "fw_try_next")) { + if (!strcasecmp(value, "A")) + return VbSetNvStorage(VBNV_FW_TRY_NEXT, 0); + else if (!strcasecmp(value, "B")) + return VbSetNvStorage(VBNV_FW_TRY_NEXT, 1); + else + return -1; + + } else if (!strcasecmp(name, "fw_result")) { + int i; + + for (i = 0; i < ARRAY_SIZE(fw_results); i++) { + if (!strcasecmp(value, fw_results[i])) + return VbSetNvStorage(VBNV_FW_RESULT, i); + } + return -1; + } + + return -1; } diff --git a/tests/vboot_nvstorage_test.c b/tests/vboot_nvstorage_test.c index 63e93d9d..2d096182 100644 --- a/tests/vboot_nvstorage_test.c +++ b/tests/vboot_nvstorage_test.c @@ -37,6 +37,10 @@ static VbNvField nvfields[] = { {VBNV_CLEAR_TPM_OWNER_REQUEST, 0, 1, 0, "clear tpm owner request"}, {VBNV_CLEAR_TPM_OWNER_DONE, 0, 1, 0, "clear tpm owner done"}, {VBNV_OPROM_NEEDED, 0, 1, 0, "oprom needed"}, + {VBNV_FW_TRY_COUNT, 0, 8, 15, "try count"}, + {VBNV_FW_TRY_NEXT, 0, 1, 0, "try next"}, + {VBNV_FW_TRIED, 0, 1, 0, "firmware tried"}, + {VBNV_FW_RESULT, VBNV_FW_RESULT_UNKNOWN, 1, 2, "firmware result"}, {0, 0, 0, 0, NULL} }; @@ -125,17 +129,22 @@ static void VbNvStorageTest(void) { /* Test other fields */ VbNvSetup(&c); + /* Test all defaults first, since some fields alias onto others */ for (vnf = nvfields; vnf->desc; vnf++) { - TEST_EQ(VbNvGet(&c, vnf->param, &data), 0, vnf->desc); - TEST_EQ(data, vnf->default_value, vnf->desc); - - TEST_EQ(VbNvSet(&c, vnf->param, vnf->test_value), 0, vnf->desc); - TEST_EQ(VbNvGet(&c, vnf->param, &data), 0, vnf->desc); - TEST_EQ(data, vnf->test_value, vnf->desc); - - TEST_EQ(VbNvSet(&c, vnf->param, vnf->test_value2), 0, vnf->desc); - TEST_EQ(VbNvGet(&c, vnf->param, &data), 0, vnf->desc); - TEST_EQ(data, vnf->test_value2, vnf->desc); + printf("Testing field: %s\n", vnf->desc); + TEST_EQ(VbNvGet(&c, vnf->param, &data), 0, " get"); + TEST_EQ(data, vnf->default_value, " default"); + } + /* Now test get/set */ + for (vnf = nvfields; vnf->desc; vnf++) { + printf("Testing field: %s\n", vnf->desc); + TEST_EQ(VbNvSet(&c, vnf->param, vnf->test_value), 0, " set 1"); + TEST_EQ(VbNvGet(&c, vnf->param, &data), 0, " get 1"); + TEST_EQ(data, vnf->test_value, " value 1"); + + TEST_EQ(VbNvSet(&c, vnf->param, vnf->test_value2), 0, " set 2"); + TEST_EQ(VbNvGet(&c, vnf->param, &data), 0, " get 2"); + TEST_EQ(data, vnf->test_value2, " value 2"); } VbNvTeardown(&c); @@ -161,12 +170,19 @@ static void VbNvStorageTest(void) { VbNvSet(&c, VBNV_TRY_B_COUNT, 16); VbNvGet(&c, VBNV_TRY_B_COUNT, &data); TEST_EQ(data, 15, "Try b count out of range"); + VbNvSetup(&c); + VbNvSet(&c, VBNV_FW_TRY_COUNT, 16); + VbNvGet(&c, VBNV_FW_TRY_COUNT, &data); + TEST_EQ(data, 15, "Try count out of range"); VbNvSet(&c, VBNV_RECOVERY_REQUEST, 0x101); VbNvGet(&c, VBNV_RECOVERY_REQUEST, &data); TEST_EQ(data, VBNV_RECOVERY_LEGACY, "Recovery request out of range"); VbNvSet(&c, VBNV_LOCALIZATION_INDEX, 0x102); VbNvGet(&c, VBNV_LOCALIZATION_INDEX, &data); TEST_EQ(data, 0, "Localization index out of range"); + VbNvSet(&c, VBNV_FW_RESULT, VBNV_FW_RESULT_UNKNOWN + 100); + VbNvGet(&c, VBNV_FW_RESULT, &data); + TEST_EQ(data, VBNV_FW_RESULT_UNKNOWN, "Firmware result out of range"); VbNvTeardown(&c); } diff --git a/utility/crossystem.c b/utility/crossystem.c index 6b16ff40..5251f7d7 100644 --- a/utility/crossystem.c +++ b/utility/crossystem.c @@ -57,6 +57,12 @@ const Param sys_param_list[] = { {"fwid", IS_STRING, "Active firmware ID"}, {"fwupdate_tries", CAN_WRITE, "Times to try OS firmware update (writable, inside kern_nv)"}, + {"fw_tried", IS_STRING, "Firmware tried this boot (vboot2)"}, + {"fw_try_count", CAN_WRITE, "Number of times to try fw_try_next (writable)"}, + {"fw_try_next", IS_STRING|CAN_WRITE, + "Firmware to try next (vboot2,writable)"}, + {"fw_result", IS_STRING|CAN_WRITE, + "Firmware result this boot (vboot2,writable)"}, {"hwid", IS_STRING, "Hardware ID"}, {"kern_nv", 0, "Non-volatile field for kernel use", "0x%08x"}, {"kernkey_vfy", IS_STRING, "Type of verification done on kernel key block"}, |