summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/2lib/2misc.c4
-rw-r--r--firmware/2lib/2nvstorage.c28
-rw-r--r--firmware/2lib/include/2nvstorage.h6
-rw-r--r--firmware/include/vboot_nvstorage.h5
-rw-r--r--firmware/lib/vboot_nvstorage.c28
-rw-r--r--host/lib/crossystem.c8
-rw-r--r--tests/vb2_misc_tests.c17
-rw-r--r--tests/vb2_nvstorage_tests.c2
-rw-r--r--tests/vboot_nvstorage_test.c2
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}
};