diff options
-rw-r--r-- | firmware/2lib/2misc.c | 4 | ||||
-rw-r--r-- | firmware/2lib/2nvstorage.c | 28 | ||||
-rw-r--r-- | firmware/2lib/include/2nvstorage.h | 6 | ||||
-rw-r--r-- | firmware/include/vboot_nvstorage.h | 5 | ||||
-rw-r--r-- | firmware/lib/vboot_nvstorage.c | 28 | ||||
-rw-r--r-- | host/lib/crossystem.c | 8 | ||||
-rw-r--r-- | tests/vb2_misc_tests.c | 17 | ||||
-rw-r--r-- | tests/vb2_nvstorage_tests.c | 2 | ||||
-rw-r--r-- | tests/vboot_nvstorage_test.c | 2 |
9 files changed, 96 insertions, 4 deletions
diff --git a/firmware/2lib/2misc.c b/firmware/2lib/2misc.c index 94ad0c3b..bcf5b362 100644 --- a/firmware/2lib/2misc.c +++ b/firmware/2lib/2misc.c @@ -316,6 +316,10 @@ int vb2_select_fw_slot(struct vb2_context *ctx) sd->last_fw_slot = vb2_nv_get(ctx, VB2_NV_FW_TRIED); sd->last_fw_result = vb2_nv_get(ctx, VB2_NV_FW_RESULT); + /* Save to the previous result fields in NV storage */ + vb2_nv_set(ctx, VB2_NV_FW_PREV_TRIED, sd->last_fw_slot); + vb2_nv_set(ctx, VB2_NV_FW_PREV_RESULT, sd->last_fw_result); + /* Clear result, since we don't know what will happen this boot */ vb2_nv_set(ctx, VB2_NV_FW_RESULT, VB2_FW_RESULT_UNKNOWN); diff --git a/firmware/2lib/2nvstorage.c b/firmware/2lib/2nvstorage.c index 02904741..5c7b9800 100644 --- a/firmware/2lib/2nvstorage.c +++ b/firmware/2lib/2nvstorage.c @@ -31,7 +31,7 @@ enum vb2_nv_offset { VB2_NV_OFFS_TPM = 5, VB2_NV_OFFS_RECOVERY_SUBCODE = 6, VB2_NV_OFFS_BOOT2 = 7, - /* Offsets 7-10 are currently unused */ + /* Offsets 8-10 are currently unused */ VB2_NV_OFFS_KERNEL = 11, /* 11-14; field is 32 bits */ /* CRC must be last field */ VB2_NV_OFFS_CRC = 15 @@ -50,10 +50,13 @@ enum vb2_nv_offset { #define VB2_NV_BOOT_DISABLE_DEV 0x40 #define VB2_NV_BOOT_DEBUG_RESET 0x80 -/* Fields in VB2_NV_OFFS_BOOT2 (unused = 0xf0) */ +/* Fields in VB2_NV_OFFS_BOOT2 (unused = 0x80) */ #define VB2_NV_BOOT2_RESULT_MASK 0x03 #define VB2_NV_BOOT2_TRIED 0x04 #define VB2_NV_BOOT2_TRY_NEXT 0x08 +#define VB2_NV_BOOT2_PREV_RESULT_MASK 0x30 +#define VB2_NV_BOOT2_PREV_RESULT_SHIFT 4 /* Number of bits to shift result */ +#define VB2_NV_BOOT2_PREV_TRIED 0x40 /* Fields in VB2_NV_OFFS_DEV (unused = 0xf8) */ #define VB2_NV_DEV_FLAG_USB 0x01 @@ -156,6 +159,13 @@ uint32_t vb2_nv_get(struct vb2_context *ctx, enum vb2_nv_param param) case VB2_NV_FW_RESULT: return p[VB2_NV_OFFS_BOOT2] & VB2_NV_BOOT2_RESULT_MASK; + case VB2_NV_FW_PREV_TRIED: + return GETBIT(VB2_NV_OFFS_BOOT2, VB2_NV_BOOT2_PREV_TRIED); + + case VB2_NV_FW_PREV_RESULT: + return (p[VB2_NV_OFFS_BOOT2] & VB2_NV_BOOT2_PREV_RESULT_MASK) + >> VB2_NV_BOOT2_PREV_RESULT_SHIFT; + case VB2_NV_RECOVERY_REQUEST: return p[VB2_NV_OFFS_RECOVERY]; @@ -262,6 +272,20 @@ void vb2_nv_set(struct vb2_context *ctx, p[VB2_NV_OFFS_BOOT2] |= (uint8_t)value; break; + case VB2_NV_FW_PREV_TRIED: + SETBIT(VB2_NV_OFFS_BOOT2, VB2_NV_BOOT2_PREV_TRIED); + break; + + case VB2_NV_FW_PREV_RESULT: + /* Map out of range values to unknown */ + if (value > VB2_NV_BOOT2_RESULT_MASK) + value = VB2_FW_RESULT_UNKNOWN; + + p[VB2_NV_OFFS_BOOT2] &= ~VB2_NV_BOOT2_PREV_RESULT_MASK; + p[VB2_NV_OFFS_BOOT2] |= + (uint8_t)(value << VB2_NV_BOOT2_PREV_RESULT_SHIFT); + break; + case VB2_NV_RECOVERY_REQUEST: /* * Map values outside the valid range to the legacy reason, diff --git a/firmware/2lib/include/2nvstorage.h b/firmware/2lib/include/2nvstorage.h index 11a77966..3bda9d78 100644 --- a/firmware/2lib/include/2nvstorage.h +++ b/firmware/2lib/include/2nvstorage.h @@ -74,9 +74,13 @@ enum vb2_nv_param { VB2_NV_FW_TRIED, /* Result of trying that firmware (see vb2_fw_result) */ VB2_NV_FW_RESULT, + /* Firmware slot tried previous boot (0=A, 1=B) */ + VB2_NV_FW_PREV_TRIED, + /* Result of trying that firmware (see vb2_fw_result) */ + VB2_NV_FW_PREV_RESULT, }; -/* Result of trying the firmware in VB2_NV_FW_TRIED */ +/* Firmware result codes for VB2_NV_FW_RESULT and VB2_NV_FW_PREV_RESULT */ enum vb2_fw_result { /* Unknown */ VB2_FW_RESULT_UNKNOWN = 0, diff --git a/firmware/include/vboot_nvstorage.h b/firmware/include/vboot_nvstorage.h index 0a9a4841..f71a55ab 100644 --- a/firmware/include/vboot_nvstorage.h +++ b/firmware/include/vboot_nvstorage.h @@ -98,7 +98,10 @@ typedef enum VbNvParam { VBNV_FW_TRIED, /* Vboot2: Result of trying that firmware (see vb2_fw_result) */ VBNV_FW_RESULT, - + /* Firmware slot tried previous boot (0=A, 1=B) */ + VBNV_FW_PREV_TRIED, + /* Result of trying that firmware (see vb2_fw_result) */ + VBNV_FW_PREV_RESULT, } VbNvParam; diff --git a/firmware/lib/vboot_nvstorage.c b/firmware/lib/vboot_nvstorage.c index 5476e85b..a0721d7c 100644 --- a/firmware/lib/vboot_nvstorage.c +++ b/firmware/lib/vboot_nvstorage.c @@ -51,6 +51,9 @@ #define BOOT2_RESULT_MASK 0x03 #define BOOT2_TRIED 0x04 #define BOOT2_TRY_NEXT 0x08 +#define BOOT2_PREV_RESULT_MASK 0x30 +#define BOOT2_PREV_RESULT_SHIFT 4 /* Number of bits to shift result */ +#define BOOT2_PREV_TRIED 0x40 #define KERNEL_FIELD_OFFSET 11 #define CRC_OFFSET 15 @@ -179,6 +182,15 @@ int VbNvGet(VbNvContext *context, VbNvParam param, uint32_t *dest) *dest = raw[BOOT2_OFFSET] & BOOT2_RESULT_MASK; return 0; + case VBNV_FW_PREV_TRIED: + *dest = (raw[BOOT2_OFFSET] & BOOT2_PREV_TRIED ? 1 : 0); + return 0; + + case VBNV_FW_PREV_RESULT: + *dest = (raw[BOOT2_OFFSET] & BOOT2_PREV_RESULT_MASK) + >> BOOT2_PREV_RESULT_SHIFT; + return 0; + default: return 1; } @@ -333,6 +345,22 @@ int VbNvSet(VbNvContext *context, VbNvParam param, uint32_t value) raw[BOOT2_OFFSET] |= (uint8_t)value; break; + case VBNV_FW_PREV_TRIED: + if (value) + raw[BOOT2_OFFSET] |= BOOT2_PREV_TRIED; + else + raw[BOOT2_OFFSET] &= ~BOOT2_PREV_TRIED; + break; + + case VBNV_FW_PREV_RESULT: + /* Map out of range values to unknown */ + if (value > BOOT2_RESULT_MASK) + value = VBNV_FW_RESULT_UNKNOWN; + + raw[BOOT2_OFFSET] &= ~BOOT2_PREV_RESULT_MASK; + raw[BOOT2_OFFSET] |= (uint8_t)value << BOOT2_PREV_RESULT_SHIFT; + break; + default: return 1; } diff --git a/host/lib/crossystem.c b/host/lib/crossystem.c index d6555c67..b28fd877 100644 --- a/host/lib/crossystem.c +++ b/host/lib/crossystem.c @@ -560,6 +560,14 @@ const char* VbGetSystemPropertyString(const char* name, char* dest, return fw_results[v]; else return "unknown"; + } else if (!strcasecmp(name, "fw_prev_tried")) { + return VbGetNvStorage(VBNV_FW_PREV_TRIED) ? "B" : "A"; + } else if (!strcasecmp(name, "fw_prev_result")) { + int v = VbGetNvStorage(VBNV_FW_PREV_RESULT); + if (v < ARRAY_SIZE(fw_results)) + return fw_results[v]; + else + return "unknown"; } return NULL; diff --git a/tests/vb2_misc_tests.c b/tests/vb2_misc_tests.c index 72c284c6..6155f23e 100644 --- a/tests/vb2_misc_tests.c +++ b/tests/vb2_misc_tests.c @@ -450,6 +450,23 @@ static void select_slot_tests(void) TEST_EQ(sd->fw_slot, 0, "selected A"); TEST_EQ(cc.flags & VB2_CONTEXT_FW_SLOT_B, 0, "didn't choose B"); TEST_EQ(vb2_nv_get(&cc, VB2_NV_TRY_COUNT), 2, "tries decremented"); + + /* Tried/result get copied to the previous fields */ + reset_common_data(); + vb2_nv_set(&cc, VB2_NV_FW_TRIED, 0); + vb2_nv_set(&cc, VB2_NV_FW_RESULT, VB2_FW_RESULT_SUCCESS); + vb2_select_fw_slot(&cc); + TEST_EQ(vb2_nv_get(&cc, VB2_NV_FW_PREV_TRIED), 0, "prev A"); + TEST_EQ(vb2_nv_get(&cc, VB2_NV_FW_PREV_RESULT), VB2_FW_RESULT_SUCCESS, + "prev success"); + + reset_common_data(); + vb2_nv_set(&cc, VB2_NV_FW_TRIED, 1); + vb2_nv_set(&cc, VB2_NV_FW_RESULT, VB2_FW_RESULT_FAILURE); + vb2_select_fw_slot(&cc); + TEST_EQ(vb2_nv_get(&cc, VB2_NV_FW_PREV_TRIED), 1, "prev B"); + TEST_EQ(vb2_nv_get(&cc, VB2_NV_FW_PREV_RESULT), VB2_FW_RESULT_FAILURE, + "prev failure"); } int main(int argc, char* argv[]) diff --git a/tests/vb2_nvstorage_tests.c b/tests/vb2_nvstorage_tests.c index b648ca95..46547f8f 100644 --- a/tests/vb2_nvstorage_tests.c +++ b/tests/vb2_nvstorage_tests.c @@ -34,6 +34,8 @@ static struct nv_field nvfields[] = { {VB2_NV_TRY_COUNT, 0, 6, 15, "try B count"}, {VB2_NV_FW_TRIED, 0, 1, 0, "firmware tried"}, {VB2_NV_FW_RESULT, 0, 1, 2, "firmware result"}, + {VB2_NV_FW_PREV_TRIED, 0, 1, 0, "firmware prev tried"}, + {VB2_NV_FW_PREV_RESULT, 0, 1, 3, "firmware prev result"}, {VB2_NV_RECOVERY_REQUEST, 0, 0x42, 0xED, "recovery request"}, {VB2_NV_RECOVERY_SUBCODE, 0, 0x56, 0xAC, "recovery subcode"}, {VB2_NV_LOCALIZATION_INDEX, 0, 0x69, 0xB0, "localization index"}, diff --git a/tests/vboot_nvstorage_test.c b/tests/vboot_nvstorage_test.c index 2d096182..ec857382 100644 --- a/tests/vboot_nvstorage_test.c +++ b/tests/vboot_nvstorage_test.c @@ -41,6 +41,8 @@ static VbNvField nvfields[] = { {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"}, + {VBNV_FW_PREV_TRIED, 0, 1, 0, "firmware prev tried"}, + {VBNV_FW_PREV_RESULT, VBNV_FW_RESULT_UNKNOWN, 1, 3, "firmware prev result"}, {0, 0, 0, 0, NULL} }; |