mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-24 02:05:01 +00:00
vboot2: Add previously tried slot and result to NV storage
This gives recovery mode information on two boots back instead of one, which may be handy for debugging. It also allows determining whether a failure of the current boot should try the other slot or go to recovery, using only information stored in NV storage. Added crossystem support for printing the fields, and unit tests. BUG=chrome-os-partner:32585 BRANCH=none TEST=make runtests; VBOOT2=1 make runtests Change-Id: Ia9f4186210d30217b902db7c513ae4ab8851f8f4 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/221230 Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
This commit is contained in:
committed by
chrome-internal-fetch
parent
80872dbffc
commit
782300d093
@@ -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_slot = vb2_nv_get(ctx, VB2_NV_FW_TRIED);
|
||||||
sd->last_fw_result = vb2_nv_get(ctx, VB2_NV_FW_RESULT);
|
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 */
|
/* Clear result, since we don't know what will happen this boot */
|
||||||
vb2_nv_set(ctx, VB2_NV_FW_RESULT, VB2_FW_RESULT_UNKNOWN);
|
vb2_nv_set(ctx, VB2_NV_FW_RESULT, VB2_FW_RESULT_UNKNOWN);
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ enum vb2_nv_offset {
|
|||||||
VB2_NV_OFFS_TPM = 5,
|
VB2_NV_OFFS_TPM = 5,
|
||||||
VB2_NV_OFFS_RECOVERY_SUBCODE = 6,
|
VB2_NV_OFFS_RECOVERY_SUBCODE = 6,
|
||||||
VB2_NV_OFFS_BOOT2 = 7,
|
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 */
|
VB2_NV_OFFS_KERNEL = 11, /* 11-14; field is 32 bits */
|
||||||
/* CRC must be last field */
|
/* CRC must be last field */
|
||||||
VB2_NV_OFFS_CRC = 15
|
VB2_NV_OFFS_CRC = 15
|
||||||
@@ -50,10 +50,13 @@ enum vb2_nv_offset {
|
|||||||
#define VB2_NV_BOOT_DISABLE_DEV 0x40
|
#define VB2_NV_BOOT_DISABLE_DEV 0x40
|
||||||
#define VB2_NV_BOOT_DEBUG_RESET 0x80
|
#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_RESULT_MASK 0x03
|
||||||
#define VB2_NV_BOOT2_TRIED 0x04
|
#define VB2_NV_BOOT2_TRIED 0x04
|
||||||
#define VB2_NV_BOOT2_TRY_NEXT 0x08
|
#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) */
|
/* Fields in VB2_NV_OFFS_DEV (unused = 0xf8) */
|
||||||
#define VB2_NV_DEV_FLAG_USB 0x01
|
#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:
|
case VB2_NV_FW_RESULT:
|
||||||
return p[VB2_NV_OFFS_BOOT2] & VB2_NV_BOOT2_RESULT_MASK;
|
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:
|
case VB2_NV_RECOVERY_REQUEST:
|
||||||
return p[VB2_NV_OFFS_RECOVERY];
|
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;
|
p[VB2_NV_OFFS_BOOT2] |= (uint8_t)value;
|
||||||
break;
|
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:
|
case VB2_NV_RECOVERY_REQUEST:
|
||||||
/*
|
/*
|
||||||
* Map values outside the valid range to the legacy reason,
|
* Map values outside the valid range to the legacy reason,
|
||||||
|
|||||||
@@ -74,9 +74,13 @@ enum vb2_nv_param {
|
|||||||
VB2_NV_FW_TRIED,
|
VB2_NV_FW_TRIED,
|
||||||
/* Result of trying that firmware (see vb2_fw_result) */
|
/* Result of trying that firmware (see vb2_fw_result) */
|
||||||
VB2_NV_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 {
|
enum vb2_fw_result {
|
||||||
/* Unknown */
|
/* Unknown */
|
||||||
VB2_FW_RESULT_UNKNOWN = 0,
|
VB2_FW_RESULT_UNKNOWN = 0,
|
||||||
|
|||||||
@@ -98,7 +98,10 @@ typedef enum VbNvParam {
|
|||||||
VBNV_FW_TRIED,
|
VBNV_FW_TRIED,
|
||||||
/* Vboot2: Result of trying that firmware (see vb2_fw_result) */
|
/* Vboot2: Result of trying that firmware (see vb2_fw_result) */
|
||||||
VBNV_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;
|
} VbNvParam;
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,9 @@
|
|||||||
#define BOOT2_RESULT_MASK 0x03
|
#define BOOT2_RESULT_MASK 0x03
|
||||||
#define BOOT2_TRIED 0x04
|
#define BOOT2_TRIED 0x04
|
||||||
#define BOOT2_TRY_NEXT 0x08
|
#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 KERNEL_FIELD_OFFSET 11
|
||||||
#define CRC_OFFSET 15
|
#define CRC_OFFSET 15
|
||||||
@@ -179,6 +182,15 @@ int VbNvGet(VbNvContext *context, VbNvParam param, uint32_t *dest)
|
|||||||
*dest = raw[BOOT2_OFFSET] & BOOT2_RESULT_MASK;
|
*dest = raw[BOOT2_OFFSET] & BOOT2_RESULT_MASK;
|
||||||
return 0;
|
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:
|
default:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -333,6 +345,22 @@ int VbNvSet(VbNvContext *context, VbNvParam param, uint32_t value)
|
|||||||
raw[BOOT2_OFFSET] |= (uint8_t)value;
|
raw[BOOT2_OFFSET] |= (uint8_t)value;
|
||||||
break;
|
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:
|
default:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -560,6 +560,14 @@ const char* VbGetSystemPropertyString(const char* name, char* dest,
|
|||||||
return fw_results[v];
|
return fw_results[v];
|
||||||
else
|
else
|
||||||
return "unknown";
|
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;
|
return NULL;
|
||||||
|
|||||||
@@ -450,6 +450,23 @@ static void select_slot_tests(void)
|
|||||||
TEST_EQ(sd->fw_slot, 0, "selected A");
|
TEST_EQ(sd->fw_slot, 0, "selected A");
|
||||||
TEST_EQ(cc.flags & VB2_CONTEXT_FW_SLOT_B, 0, "didn't choose B");
|
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");
|
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[])
|
int main(int argc, char* argv[])
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ static struct nv_field nvfields[] = {
|
|||||||
{VB2_NV_TRY_COUNT, 0, 6, 15, "try B count"},
|
{VB2_NV_TRY_COUNT, 0, 6, 15, "try B count"},
|
||||||
{VB2_NV_FW_TRIED, 0, 1, 0, "firmware tried"},
|
{VB2_NV_FW_TRIED, 0, 1, 0, "firmware tried"},
|
||||||
{VB2_NV_FW_RESULT, 0, 1, 2, "firmware result"},
|
{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_REQUEST, 0, 0x42, 0xED, "recovery request"},
|
||||||
{VB2_NV_RECOVERY_SUBCODE, 0, 0x56, 0xAC, "recovery subcode"},
|
{VB2_NV_RECOVERY_SUBCODE, 0, 0x56, 0xAC, "recovery subcode"},
|
||||||
{VB2_NV_LOCALIZATION_INDEX, 0, 0x69, 0xB0, "localization index"},
|
{VB2_NV_LOCALIZATION_INDEX, 0, 0x69, 0xB0, "localization index"},
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ static VbNvField nvfields[] = {
|
|||||||
{VBNV_FW_TRY_NEXT, 0, 1, 0, "try next"},
|
{VBNV_FW_TRY_NEXT, 0, 1, 0, "try next"},
|
||||||
{VBNV_FW_TRIED, 0, 1, 0, "firmware tried"},
|
{VBNV_FW_TRIED, 0, 1, 0, "firmware tried"},
|
||||||
{VBNV_FW_RESULT, VBNV_FW_RESULT_UNKNOWN, 1, 2, "firmware result"},
|
{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}
|
{0, 0, 0, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user