| /* Copyright 2014 The ChromiumOS Authors | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| * | |
| * Tests for misc library | |
| */ | |
| #include "2api.h" | |
| #include "2common.h" | |
| #include "2misc.h" | |
| #include "2nvstorage.h" | |
| #include "2secdata.h" | |
| #include "2sysincludes.h" | |
| #include "common/boot_mode.h" | |
| #include "common/tests.h" | |
| /* Common context for tests */ | |
| static uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE] | |
| __attribute__((aligned(VB2_WORKBUF_ALIGN))); | |
| static uint8_t workbuf2[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE] | |
| __attribute__((aligned(VB2_WORKBUF_ALIGN))); | |
| static struct vb2_context *ctx; | |
| static struct vb2_shared_data *sd; | |
| static struct vb2_gbb_header gbb; | |
| static struct vb2_secdata_fwmp *fwmp; | |
| /* Mocked function data */ | |
| static enum vb2_resource_index mock_resource_index; | |
| static void *mock_resource_ptr; | |
| static uint32_t mock_resource_size; | |
| static int mock_tpm_clear_called; | |
| static int mock_tpm_clear_retval; | |
| static void reset_common_data(void) | |
| { | |
| memset(workbuf, 0xaa, sizeof(workbuf)); | |
| memset(workbuf2, 0xbb, sizeof(workbuf2)); | |
| TEST_SUCC(vb2api_init(workbuf, sizeof(workbuf), &ctx), | |
| "vb2api_init failed"); | |
| sd = vb2_get_sd(ctx); | |
| sd->status |= VB2_SD_STATUS_SECDATA_FWMP_INIT; | |
| memset(&gbb, 0, sizeof(gbb)); | |
| vb2_nv_init(ctx); | |
| vb2api_secdata_firmware_create(ctx); | |
| vb2_secdata_firmware_init(ctx); | |
| fwmp = (struct vb2_secdata_fwmp *)&ctx->secdata_fwmp; | |
| mock_tpm_clear_called = 0; | |
| mock_tpm_clear_retval = VB2_SUCCESS; | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_NORMAL); | |
| }; | |
| /* Mocked functions */ | |
| struct vb2_gbb_header *vb2_get_gbb(struct vb2_context *c) | |
| { | |
| return &gbb; | |
| } | |
| vb2_error_t vb2ex_read_resource(struct vb2_context *c, | |
| enum vb2_resource_index index, uint32_t offset, | |
| void *buf, uint32_t size) | |
| { | |
| if (index != mock_resource_index) | |
| return VB2_ERROR_EX_READ_RESOURCE_INDEX; | |
| if (offset > mock_resource_size || offset + size > mock_resource_size) | |
| return VB2_ERROR_EX_READ_RESOURCE_SIZE; | |
| memcpy(buf, (uint8_t *)mock_resource_ptr + offset, size); | |
| return VB2_SUCCESS; | |
| } | |
| vb2_error_t vb2ex_tpm_clear_owner(struct vb2_context *c) | |
| { | |
| mock_tpm_clear_called++; | |
| return mock_tpm_clear_retval; | |
| } | |
| /* Tests */ | |
| static void init_workbuf_tests(void) | |
| { | |
| struct vb2_context *orig_ctx; | |
| /* check constants */ | |
| TEST_TRUE(sizeof(struct vb2_context) < VB2_CONTEXT_MAX_SIZE, | |
| "vb2_context max size constant"); | |
| /* vb2api_init() - misaligned */ | |
| TEST_EQ(vb2api_init(workbuf + 1, sizeof(workbuf) - 1, &ctx), | |
| VB2_ERROR_WORKBUF_ALIGN, "vb2api_init - misaligned"); | |
| /* vb2api_init() - size too small */ | |
| TEST_EQ(vb2api_init(workbuf, sizeof(struct vb2_shared_data) - 1, | |
| &ctx), VB2_ERROR_WORKBUF_SMALL, | |
| "vb2api_init - size too small"); | |
| /* vb2api_init() - success */ | |
| TEST_SUCC(vb2api_init(workbuf, sizeof(workbuf), &ctx), | |
| "vb2api_init - success"); | |
| TEST_TRUE((uintptr_t)workbuf < (uintptr_t)ctx && | |
| (uintptr_t)ctx < (uintptr_t)workbuf + sizeof(workbuf), | |
| " return proper pointer"); | |
| struct vb2_context zero_ctx = {0}; | |
| TEST_SUCC(memcmp(ctx, &zero_ctx, sizeof(struct vb2_context)), | |
| " vb2_context set to zero"); | |
| sd = vb2_get_sd(ctx); | |
| TEST_EQ(sd->magic, VB2_SHARED_DATA_MAGIC, " set magic"); | |
| TEST_EQ(sd->struct_version_major, VB2_SHARED_DATA_VERSION_MAJOR, | |
| " set major version"); | |
| TEST_EQ(sd->struct_version_minor, VB2_SHARED_DATA_VERSION_MINOR, | |
| " set minor version"); | |
| TEST_EQ(sd->workbuf_size, sizeof(workbuf), " set workbuf size"); | |
| TEST_TRUE(sd->workbuf_used - sizeof(struct vb2_shared_data) | |
| < VB2_WORKBUF_ALIGN, " set workbuf used"); | |
| /* vb2api_relocate() - misaligned source */ | |
| reset_common_data(); | |
| memmove(workbuf + 1, workbuf, sizeof(workbuf) - 1); | |
| TEST_SUCC(vb2api_relocate(workbuf2, workbuf + 1, sizeof(workbuf) - 1, | |
| &ctx), "vb2api_relocate - misaligned source"); | |
| /* vb2api_relocate() - misaligned target */ | |
| reset_common_data(); | |
| TEST_EQ(vb2api_relocate(workbuf2 + 1, workbuf, sizeof(workbuf) - 1, | |
| &ctx), | |
| VB2_ERROR_WORKBUF_ALIGN, "vb2api_relocate - misaligned target"); | |
| /* vb2api_relocate() - bad magic */ | |
| reset_common_data(); | |
| sd->magic = 0; | |
| TEST_EQ(vb2api_relocate(workbuf2, workbuf, sizeof(workbuf), &ctx), | |
| VB2_ERROR_SHARED_DATA_MAGIC, "vb2api_relocate - bad magic"); | |
| /* vb2api_relocate() - small major version */ | |
| reset_common_data(); | |
| sd->struct_version_major--; | |
| TEST_EQ(vb2api_relocate(workbuf2, workbuf, sizeof(workbuf), &ctx), | |
| VB2_ERROR_SHARED_DATA_VERSION, | |
| "vb2api_relocate - small major version"); | |
| /* vb2api_relocate() - big major version */ | |
| reset_common_data(); | |
| sd->struct_version_major++; | |
| TEST_EQ(vb2api_relocate(workbuf2, workbuf, sizeof(workbuf), &ctx), | |
| VB2_ERROR_SHARED_DATA_VERSION, | |
| "vb2api_relocate - big major version"); | |
| /* vb2api_relocate() - small minor version */ | |
| if (VB2_SHARED_DATA_VERSION_MINOR > 0) { | |
| reset_common_data(); | |
| sd->struct_version_minor--; | |
| TEST_EQ(vb2api_relocate(workbuf2, workbuf, sizeof(workbuf), | |
| &ctx), | |
| VB2_ERROR_SHARED_DATA_VERSION, | |
| "vb2api_relocate - small minor version"); | |
| } | |
| /* vb2api_relocate() - big minor version */ | |
| reset_common_data(); | |
| sd->struct_version_minor++; | |
| TEST_SUCC(vb2api_relocate(workbuf2, workbuf, sizeof(workbuf), &ctx), | |
| "vb2api_relocate - big minor version"); | |
| /* vb2api_relocate() - small workbuf_used */ | |
| reset_common_data(); | |
| sd->workbuf_used = sizeof(struct vb2_shared_data) - 1; | |
| TEST_EQ(vb2api_relocate(workbuf2, workbuf, sizeof(workbuf), &ctx), | |
| VB2_ERROR_WORKBUF_INVALID, | |
| "vb2api_relocate - small workbuf_used"); | |
| /* vb2api_relocate() - workbuf_size < workbuf_used */ | |
| reset_common_data(); | |
| sd->workbuf_used = sd->workbuf_size; | |
| sd->workbuf_size--; | |
| TEST_EQ(vb2api_relocate(workbuf2, workbuf, sizeof(workbuf), &ctx), | |
| VB2_ERROR_WORKBUF_INVALID, | |
| "vb2api_relocate - workbuf_size < workbuf_used"); | |
| /* vb2api_relocate() - target workbuf too small */ | |
| reset_common_data(); | |
| sd->workbuf_used = sd->workbuf_size - 1; | |
| TEST_EQ(vb2api_relocate(workbuf2, workbuf, sd->workbuf_used - 1, &ctx), | |
| VB2_ERROR_WORKBUF_SMALL, | |
| "vb2api_relocate - target workbuf too small"); | |
| /* vb2api_relocate() - success (same size) */ | |
| reset_common_data(); | |
| orig_ctx = ctx; | |
| TEST_SUCC(vb2api_relocate(workbuf2, workbuf, sizeof(workbuf), &ctx), | |
| "vb2api_relocate - success (same size)"); | |
| sd = vb2_get_sd(ctx); | |
| TEST_EQ((uintptr_t)orig_ctx - (uintptr_t)workbuf, | |
| (uintptr_t)ctx - (uintptr_t)workbuf2, | |
| " same context pointer"); | |
| TEST_SUCC(memcmp(workbuf2, workbuf, sd->workbuf_used), | |
| " same workbuf"); | |
| /* vb2api_relocate() - success (smaller size) */ | |
| reset_common_data(); | |
| TEST_SUCC(vb2api_relocate(workbuf2, workbuf, sizeof(workbuf) - 1, &ctx), | |
| "vb2api_relocate - success (smaller size)"); | |
| sd = vb2_get_sd(ctx); | |
| TEST_EQ(sd->workbuf_size, sizeof(workbuf) - 1, " set workbuf size"); | |
| /* vb2api_relocate() - success (larger size) */ | |
| reset_common_data(); | |
| sd->workbuf_size--; | |
| TEST_SUCC(vb2api_relocate(workbuf2, workbuf, sizeof(workbuf), &ctx), | |
| "vb2api_relocate - success (larger size)"); | |
| sd = vb2_get_sd(ctx); | |
| TEST_EQ(sd->workbuf_size, sizeof(workbuf), " set workbuf size"); | |
| /* vb2api_relocate() - success (overlapping) */ | |
| reset_common_data(); | |
| orig_ctx = ctx; | |
| sd->workbuf_size -= VB2_WORKBUF_ALIGN; | |
| memcpy(workbuf2, workbuf, sd->workbuf_used); | |
| TEST_SUCC(vb2api_relocate(workbuf + VB2_WORKBUF_ALIGN, workbuf, | |
| sizeof(workbuf) - VB2_WORKBUF_ALIGN, &ctx), | |
| "vb2api_relocate - success (overlapping)"); | |
| sd = vb2_get_sd(ctx); | |
| TEST_EQ((uintptr_t)ctx - (uintptr_t)orig_ctx, | |
| VB2_WORKBUF_ALIGN, | |
| " context pointer moved"); | |
| TEST_SUCC(memcmp(workbuf2, workbuf + VB2_WORKBUF_ALIGN, | |
| sd->workbuf_used), " same workbuf"); | |
| /* vb2api_reinit() - workbuf_size < workbuf_used */ | |
| reset_common_data(); | |
| sd->workbuf_size = sd->workbuf_used - 1; | |
| TEST_EQ(vb2api_reinit(workbuf, &ctx), VB2_ERROR_WORKBUF_INVALID, | |
| "vb2api_reinit - workbuf_size < workbuf_used"); | |
| /* vb2api_reinit() - success */ | |
| reset_common_data(); | |
| orig_ctx = ctx; | |
| TEST_SUCC(vb2api_reinit(workbuf, &ctx), | |
| "vb2api_reinit - success"); | |
| TEST_EQ((uintptr_t)ctx, (uintptr_t)orig_ctx, | |
| " context pointer unchanged"); | |
| } | |
| static void misc_tests(void) | |
| { | |
| struct vb2_workbuf wb; | |
| reset_common_data(); | |
| sd->workbuf_used = VB2_WORKBUF_ALIGN; | |
| vb2_workbuf_from_ctx(ctx, &wb); | |
| TEST_PTR_EQ(wb.buf, workbuf + VB2_WORKBUF_ALIGN, | |
| "vb_workbuf_from_ctx() buf"); | |
| TEST_EQ(wb.size, sd->workbuf_size - VB2_WORKBUF_ALIGN, | |
| "vb_workbuf_from_ctx() size"); | |
| reset_common_data(); | |
| sd->status |= VB2_SD_STATUS_RECOVERY_DECIDED; | |
| TEST_ABORT(VB2_REC_OR_DIE(ctx, "die\n"), "REC_OR_DIE in normal mode"); | |
| reset_common_data(); | |
| sd->status |= VB2_SD_STATUS_RECOVERY_DECIDED; | |
| ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; | |
| VB2_REC_OR_DIE(ctx, "VB2_REC_OR_DIE() test in recovery mode\n"); | |
| /* Would exit here if it didn't work as intended. */ | |
| reset_common_data(); | |
| VB2_REC_OR_DIE(ctx, "VB2_REC_OR_DIE() test in fw_phase1\n"); | |
| } | |
| static void gbb_tests(void) | |
| { | |
| struct vb2_gbb_header gbbsrc = { | |
| .signature = {'$', 'G', 'B', 'B'}, | |
| .major_version = VB2_GBB_MAJOR_VER, | |
| .minor_version = VB2_GBB_MINOR_VER, | |
| .header_size = sizeof(struct vb2_gbb_header), | |
| .flags = 0x1234, | |
| .rootkey_offset = 240, | |
| .rootkey_size = 1040, | |
| }; | |
| struct vb2_gbb_header gbbdest; | |
| TEST_EQ(sizeof(struct vb2_gbb_header), | |
| EXPECTED_VB2_GBB_HEADER_SIZE, | |
| "sizeof(struct vb2_gbb_header)"); | |
| reset_common_data(); | |
| /* Good contents */ | |
| mock_resource_index = VB2_RES_GBB; | |
| mock_resource_ptr = &gbbsrc; | |
| mock_resource_size = sizeof(gbbsrc); | |
| TEST_SUCC(vb2_read_gbb_header(ctx, &gbbdest), "read gbb header good"); | |
| TEST_SUCC(memcmp(&gbbsrc, &gbbdest, sizeof(gbbsrc)), | |
| "read gbb contents"); | |
| mock_resource_index = VB2_RES_GBB + 1; | |
| TEST_EQ(vb2_read_gbb_header(ctx, &gbbdest), | |
| VB2_ERROR_EX_READ_RESOURCE_INDEX, "read gbb header missing"); | |
| mock_resource_index = VB2_RES_GBB; | |
| gbbsrc.signature[0]++; | |
| TEST_EQ(vb2_read_gbb_header(ctx, &gbbdest), | |
| VB2_ERROR_GBB_MAGIC, "read gbb header bad magic"); | |
| gbbsrc.signature[0]--; | |
| gbbsrc.major_version = VB2_GBB_MAJOR_VER + 1; | |
| TEST_EQ(vb2_read_gbb_header(ctx, &gbbdest), | |
| VB2_ERROR_GBB_VERSION, "read gbb header major version"); | |
| gbbsrc.major_version = VB2_GBB_MAJOR_VER; | |
| gbbsrc.minor_version = VB2_GBB_MINOR_VER + 1; | |
| TEST_SUCC(vb2_read_gbb_header(ctx, &gbbdest), | |
| "read gbb header minor++"); | |
| gbbsrc.minor_version = 1; | |
| TEST_EQ(vb2_read_gbb_header(ctx, &gbbdest), | |
| VB2_ERROR_GBB_TOO_OLD, "read gbb header 1.1 fails"); | |
| gbbsrc.minor_version = 0; | |
| TEST_EQ(vb2_read_gbb_header(ctx, &gbbdest), | |
| VB2_ERROR_GBB_TOO_OLD, "read gbb header 1.0 fails"); | |
| gbbsrc.minor_version = VB2_GBB_MINOR_VER; | |
| gbbsrc.header_size--; | |
| TEST_EQ(vb2_read_gbb_header(ctx, &gbbdest), | |
| VB2_ERROR_GBB_HEADER_SIZE, "read gbb header size"); | |
| TEST_EQ(vb2_fw_init_gbb(ctx), | |
| VB2_ERROR_GBB_HEADER_SIZE, "init gbb failure"); | |
| gbbsrc.header_size++; | |
| /* Init GBB */ | |
| int used_before = sd->workbuf_used; | |
| TEST_SUCC(vb2_fw_init_gbb(ctx), "init gbb"); | |
| /* Manually calculate the location of GBB since we have mocked out the | |
| original definition of vb2_get_gbb. */ | |
| struct vb2_gbb_header *current_gbb = vb2_member_of(sd, sd->gbb_offset); | |
| TEST_SUCC(memcmp(&gbbsrc, current_gbb, sizeof(gbbsrc)), | |
| " copy gbb contents"); | |
| TEST_TRUE(sd->workbuf_used - sizeof(gbbsrc) - used_before | |
| < VB2_WORKBUF_ALIGN, " unexpected workbuf size"); | |
| /* Workbuf failure */ | |
| reset_common_data(); | |
| sd->workbuf_used = sd->workbuf_size - 4; | |
| TEST_EQ(vb2_fw_init_gbb(ctx), | |
| VB2_ERROR_GBB_WORKBUF, "init gbb no workbuf"); | |
| /* Check for setting NO_SECDATA_FWMP context flag */ | |
| reset_common_data(); | |
| TEST_SUCC(vb2_fw_init_gbb(ctx), "init gbb"); | |
| TEST_EQ(ctx->flags & VB2_CONTEXT_NO_SECDATA_FWMP, 0, | |
| "without DISABLE_FWMP: NO_SECDATA_FWMP shouldn't be set"); | |
| reset_common_data(); | |
| gbbsrc.flags |= VB2_GBB_FLAG_DISABLE_FWMP; | |
| TEST_SUCC(vb2_fw_init_gbb(ctx), "init gbb"); | |
| TEST_NEQ(ctx->flags & VB2_CONTEXT_NO_SECDATA_FWMP, 0, | |
| "with DISABLE_FWMP: NO_SECDATA_FWMP should be set"); | |
| } | |
| static void fail_tests(void) | |
| { | |
| /* Early fail (before even NV init) */ | |
| reset_common_data(); | |
| sd->status &= ~VB2_SD_STATUS_NV_INIT; | |
| vb2api_fail(ctx, 1, 2); | |
| TEST_NEQ(sd->status & VB2_SD_STATUS_NV_INIT, 0, "vb2api_fail inits NV"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST), | |
| 1, "vb2api_fail request"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_SUBCODE), | |
| 2, "vb2api_fail subcode"); | |
| /* Repeated fail doesn't overwrite the error code */ | |
| vb2api_fail(ctx, 3, 4); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST), | |
| 1, "vb2api_fail repeat"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_SUBCODE), | |
| 2, "vb2api_fail repeat2"); | |
| /* Fail with other slot good doesn't trigger recovery */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_TRY_COUNT, 3); | |
| vb2_nv_set(ctx, VB2_NV_FW_RESULT, VB2_FW_RESULT_UNKNOWN); | |
| vb2_nv_set(ctx, VB2_NV_FW_TRIED, 0); | |
| vb2_nv_set(ctx, VB2_NV_FW_PREV_TRIED, 1); | |
| vb2_nv_set(ctx, VB2_NV_FW_PREV_RESULT, VB2_FW_RESULT_UNKNOWN); | |
| sd->status |= VB2_SD_STATUS_CHOSE_SLOT; | |
| vb2api_fail(ctx, 5, 6); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST), 0, "vb2_failover"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_RESULT), | |
| VB2_FW_RESULT_FAILURE, "vb2api_fail this fw"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_TRY_COUNT), 0, | |
| "vb2api_fail use up tries"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_TRY_NEXT), 1, | |
| "vb2api_fail try other slot"); | |
| /* Fail with other slot already failing triggers recovery */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_FW_PREV_TRIED, 0); | |
| vb2_nv_set(ctx, VB2_NV_FW_PREV_RESULT, VB2_FW_RESULT_FAILURE); | |
| vb2_nv_set(ctx, VB2_NV_FW_TRIED, 1); | |
| sd->status |= VB2_SD_STATUS_CHOSE_SLOT; | |
| vb2api_fail(ctx, 7, 8); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST), 7, | |
| "vb2api_fail both slots bad"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_RESULT), | |
| VB2_FW_RESULT_FAILURE, "vb2api_fail this fw"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_TRY_NEXT), 0, | |
| "vb2api_fail try other slot"); | |
| /* Fail with single slot already failing triggers recovery */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_FW_PREV_TRIED, 0); | |
| vb2_nv_set(ctx, VB2_NV_FW_TRIED, 0); | |
| vb2_nv_set(ctx, VB2_NV_FW_RESULT, VB2_FW_RESULT_TRYING); | |
| ctx->flags |= VB2_CONTEXT_SLOT_A_ONLY; | |
| sd->status |= VB2_SD_STATUS_CHOSE_SLOT; | |
| vb2api_fail(ctx, 9, 10); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST), 9, | |
| "vb2api_fail single slot fail"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_RESULT), | |
| VB2_FW_RESULT_FAILURE, "vb2api_fail this fw"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_TRY_NEXT), 0, | |
| "vb2api_fail did not try other slot"); | |
| } | |
| static void previous_boot_fail_tests(void) | |
| { | |
| /* Previous boot fail (before even NV init) */ | |
| /* Fail with other slot good doesn't trigger recovery */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_FW_TRIED, VB2_FW_SLOT_A); | |
| vb2_nv_set(ctx, VB2_NV_TRY_COUNT, 3); | |
| vb2_nv_set(ctx, VB2_NV_FW_RESULT, VB2_FW_RESULT_UNKNOWN); | |
| sd->status &= ~VB2_SD_STATUS_NV_INIT; | |
| vb2api_previous_boot_fail(ctx, 1, 2); | |
| TEST_NEQ(sd->status & VB2_SD_STATUS_NV_INIT, | |
| 0, "vb2api_previous_boot_fail inits NV"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST), | |
| 0, "vb2_previous_boot_fail over"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_RESULT), | |
| VB2_FW_RESULT_FAILURE, "vb2api_previous_boot_fail result"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_TRY_COUNT), | |
| 0, "vb2api_previous_boot_fail try count"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_TRY_NEXT), | |
| 1, "vb2api_previous_boot_fail FW tried"); | |
| /* Fail with other slot already failing triggers recovery */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_FW_PREV_TRIED, VB2_FW_SLOT_A); | |
| vb2_nv_set(ctx, VB2_NV_FW_PREV_RESULT, VB2_FW_RESULT_FAILURE); | |
| vb2_nv_set(ctx, VB2_NV_FW_TRIED, VB2_FW_SLOT_B); | |
| vb2_nv_set(ctx, VB2_NV_TRY_COUNT, 3); | |
| vb2_nv_set(ctx, VB2_NV_FW_RESULT, VB2_FW_RESULT_UNKNOWN); | |
| sd->status &= ~VB2_SD_STATUS_NV_INIT; | |
| vb2api_previous_boot_fail(ctx, 3, 4); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST), | |
| 3, "vb2api_previous_boot_fail both slots bad"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_RESULT), | |
| VB2_FW_RESULT_FAILURE, "vb2api_previous_boot_fail result"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_TRY_COUNT), | |
| 0, "vb2api_previous_boot_fail try count"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_TRY_NEXT), | |
| 0, "vb2api_previous_boot_fail FW tried"); | |
| /* Repeated fail doesn't overwrite the error code */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_TRY_NEXT, VB2_FW_SLOT_A); | |
| vb2_nv_set(ctx, VB2_NV_TRY_COUNT, 3); | |
| vb2_nv_set(ctx, VB2_NV_FW_RESULT, VB2_FW_RESULT_FAILURE); | |
| sd->status &= ~VB2_SD_STATUS_NV_INIT; | |
| vb2api_previous_boot_fail(ctx, 5, 6); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_RESULT), | |
| VB2_FW_RESULT_FAILURE, "vb2api_previous_boot_fail result"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_TRY_COUNT), | |
| 3, "vb2api_previous_boot_fail try count"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_TRY_NEXT), | |
| VB2_FW_SLOT_A, "vb2api_previous_boot_fail try next"); | |
| } | |
| static void recovery_tests(void) | |
| { | |
| /* No recovery */ | |
| reset_common_data(); | |
| TEST_EQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED, | |
| 0, "recovery not yet decided before testing check_recovery()"); | |
| vb2_check_recovery(ctx); | |
| TEST_EQ(sd->recovery_reason, 0, "No recovery reason"); | |
| TEST_EQ(ctx->flags & VB2_CONTEXT_RECOVERY_MODE, | |
| 0, "Not recovery mode"); | |
| TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED, | |
| 0, "Recovery decided"); | |
| /* From request */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST, 3); | |
| vb2_check_recovery(ctx); | |
| TEST_EQ(sd->recovery_reason, 3, "Recovery reason from request"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST), 3, "NV not cleared"); | |
| TEST_NEQ(ctx->flags & VB2_CONTEXT_RECOVERY_MODE, | |
| 0, "Recovery mode"); | |
| TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED, | |
| 0, "Recovery decided"); | |
| /* From request, but already failed */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST, 4); | |
| sd->recovery_reason = 5; | |
| vb2_check_recovery(ctx); | |
| TEST_EQ(sd->recovery_reason, 5, "Recovery reason already failed"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST), | |
| 4, "NV not cleared"); | |
| TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED, | |
| 0, "Recovery decided"); | |
| /* Override */ | |
| reset_common_data(); | |
| sd->recovery_reason = 6; | |
| ctx->flags |= VB2_CONTEXT_FORCE_RECOVERY_MODE; | |
| vb2_check_recovery(ctx); | |
| TEST_EQ(sd->recovery_reason, VB2_RECOVERY_RO_MANUAL, | |
| "Recovery reason forced"); | |
| TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED, | |
| 0, "Recovery decided"); | |
| /* Override subcode TRAIN_AND_REBOOT */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_RECOVERY_SUBCODE, VB2_RECOVERY_TRAIN_AND_REBOOT); | |
| ctx->flags |= VB2_CONTEXT_FORCE_RECOVERY_MODE; | |
| vb2_check_recovery(ctx); | |
| TEST_EQ(sd->recovery_reason, VB2_RECOVERY_RO_MANUAL, | |
| "Recovery reason forced"); | |
| TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED, | |
| 0, "Recovery decided"); | |
| /* Promote subcode from BROKEN screen*/ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_RECOVERY_SUBCODE, VB2_RECOVERY_US_TEST); | |
| ctx->flags |= VB2_CONTEXT_FORCE_RECOVERY_MODE; | |
| vb2_check_recovery(ctx); | |
| TEST_EQ(sd->recovery_reason, VB2_RECOVERY_US_TEST, | |
| "Recovery reason forced from BROKEN"); | |
| TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED, | |
| 0, "Recovery decided"); | |
| } | |
| static void dev_switch_tests(void) | |
| { | |
| uint32_t v; | |
| /* Normal mode */ | |
| reset_common_data(); | |
| TEST_SUCC(vb2_check_dev_switch(ctx), "dev mode off"); | |
| TEST_EQ(sd->flags & VB2_SD_FLAG_DEV_MODE_ENABLED, 0, " sd not in dev"); | |
| TEST_EQ(ctx->flags & VB2_CONTEXT_DEVELOPER_MODE, 0, " ctx not in dev"); | |
| TEST_EQ(mock_tpm_clear_called, 0, " no tpm clear"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_REQ_WIPEOUT), 0, " no nv wipeout"); | |
| /* Dev mode */ | |
| reset_common_data(); | |
| vb2_secdata_firmware_set( | |
| ctx, VB2_SECDATA_FIRMWARE_FLAGS, | |
| (VB2_SECDATA_FIRMWARE_FLAG_DEV_MODE | | |
| VB2_SECDATA_FIRMWARE_FLAG_LAST_BOOT_DEVELOPER)); | |
| TEST_SUCC(vb2_check_dev_switch(ctx), "dev mode on"); | |
| TEST_NEQ(sd->flags & VB2_SD_FLAG_DEV_MODE_ENABLED, 0, " sd in dev"); | |
| TEST_NEQ(ctx->flags & VB2_CONTEXT_DEVELOPER_MODE, 0, " ctx in dev"); | |
| TEST_EQ(mock_tpm_clear_called, 0, " no tpm clear"); | |
| /* | |
| * Any normal mode boot clears dev boot flags except boot external and | |
| * enable fastboot which are set | |
| */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_DEV_BOOT_EXTERNAL, 0); | |
| vb2_nv_set(ctx, VB2_NV_DEV_ENABLE_FASTBOOT, 0); | |
| vb2_nv_set(ctx, VB2_NV_DEV_BOOT_ALTFW, 1); | |
| vb2_nv_set(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY, 1); | |
| vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT, 1); | |
| TEST_SUCC(vb2_check_dev_switch(ctx), "dev mode off"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_DEV_BOOT_EXTERNAL), | |
| 1, " set dev boot external"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_DEV_ENABLE_FASTBOOT), | |
| 1, " set dev enable fastboot"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_DEV_BOOT_ALTFW), | |
| 0, " cleared dev boot altfw"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY), | |
| 0, " cleared dev boot signed only"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_DEV_DEFAULT_BOOT), | |
| 0, " cleared dev default boot"); | |
| /* Normal-dev transition clears TPM */ | |
| reset_common_data(); | |
| vb2_secdata_firmware_set(ctx, VB2_SECDATA_FIRMWARE_FLAGS, | |
| VB2_SECDATA_FIRMWARE_FLAG_DEV_MODE); | |
| TEST_SUCC(vb2_check_dev_switch(ctx), "to dev mode"); | |
| TEST_EQ(mock_tpm_clear_called, 1, " tpm clear"); | |
| v = vb2_secdata_firmware_get(ctx, VB2_SECDATA_FIRMWARE_FLAGS); | |
| TEST_EQ(v, (VB2_SECDATA_FIRMWARE_FLAG_DEV_MODE | | |
| VB2_SECDATA_FIRMWARE_FLAG_LAST_BOOT_DEVELOPER), | |
| " last boot developer now"); | |
| /* Dev-normal transition clears TPM too */ | |
| reset_common_data(); | |
| vb2_secdata_firmware_set(ctx, VB2_SECDATA_FIRMWARE_FLAGS, | |
| VB2_SECDATA_FIRMWARE_FLAG_LAST_BOOT_DEVELOPER); | |
| TEST_SUCC(vb2_check_dev_switch(ctx), "from dev mode"); | |
| TEST_EQ(mock_tpm_clear_called, 1, " tpm clear"); | |
| v = vb2_secdata_firmware_get(ctx, VB2_SECDATA_FIRMWARE_FLAGS); | |
| TEST_EQ(v, 0, " last boot not developer now"); | |
| /* Disable dev mode */ | |
| reset_common_data(); | |
| vb2_secdata_firmware_set( | |
| ctx, VB2_SECDATA_FIRMWARE_FLAGS, | |
| (VB2_SECDATA_FIRMWARE_FLAG_DEV_MODE | | |
| VB2_SECDATA_FIRMWARE_FLAG_LAST_BOOT_DEVELOPER)); | |
| vb2_nv_set(ctx, VB2_NV_DISABLE_DEV_REQUEST, 1); | |
| TEST_SUCC(vb2_check_dev_switch(ctx), "disable dev request"); | |
| TEST_EQ(sd->flags & VB2_SD_FLAG_DEV_MODE_ENABLED, 0, " sd not in dev"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_DISABLE_DEV_REQUEST), | |
| 0, " request cleared"); | |
| /* Force enabled by GBB */ | |
| reset_common_data(); | |
| gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON; | |
| TEST_SUCC(vb2_check_dev_switch(ctx), "dev on via gbb"); | |
| TEST_NEQ(sd->flags & VB2_SD_FLAG_DEV_MODE_ENABLED, 0, " sd in dev"); | |
| v = vb2_secdata_firmware_get(ctx, VB2_SECDATA_FIRMWARE_FLAGS); | |
| TEST_EQ(v, VB2_SECDATA_FIRMWARE_FLAG_LAST_BOOT_DEVELOPER, | |
| " doesn't set dev on in secdata_firmware " | |
| "but does set last boot dev"); | |
| TEST_EQ(mock_tpm_clear_called, 1, " tpm clear"); | |
| /* Request disable by ctx flag */ | |
| reset_common_data(); | |
| vb2_secdata_firmware_set( | |
| ctx, VB2_SECDATA_FIRMWARE_FLAGS, | |
| (VB2_SECDATA_FIRMWARE_FLAG_DEV_MODE | | |
| VB2_SECDATA_FIRMWARE_FLAG_LAST_BOOT_DEVELOPER)); | |
| ctx->flags |= VB2_CONTEXT_DISABLE_DEVELOPER_MODE; | |
| TEST_SUCC(vb2_check_dev_switch(ctx), "disable dev on ctx request"); | |
| TEST_EQ(sd->flags & VB2_SD_FLAG_DEV_MODE_ENABLED, 0, " sd not in dev"); | |
| /* Simulate clear owner failure */ | |
| reset_common_data(); | |
| vb2_secdata_firmware_set(ctx, VB2_SECDATA_FIRMWARE_FLAGS, | |
| VB2_SECDATA_FIRMWARE_FLAG_LAST_BOOT_DEVELOPER); | |
| mock_tpm_clear_retval = VB2_ERROR_EX_TPM_CLEAR_OWNER; | |
| TEST_EQ(vb2_check_dev_switch(ctx), | |
| VB2_ERROR_EX_TPM_CLEAR_OWNER, "tpm clear fail"); | |
| TEST_EQ(mock_tpm_clear_called, 1, " tpm clear"); | |
| v = vb2_secdata_firmware_get(ctx, VB2_SECDATA_FIRMWARE_FLAGS); | |
| TEST_EQ(v, VB2_SECDATA_FIRMWARE_FLAG_LAST_BOOT_DEVELOPER, | |
| " last boot still developer"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST), | |
| VB2_RECOVERY_TPM_CLEAR_OWNER, " requests recovery"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_SUBCODE), | |
| (uint8_t)VB2_ERROR_EX_TPM_CLEAR_OWNER, " recovery subcode"); | |
| /* | |
| * secdata_firmware failure in normal mode fails and shows dev=0 even | |
| * if dev mode was on in the (inaccessible) secdata_firmware. Since this | |
| * happens in fw_phase1, we do not abort -- we know that when secdata | |
| * is uninitialized here, we must be headed for recovery mode. | |
| */ | |
| reset_common_data(); | |
| vb2_secdata_firmware_set(ctx, VB2_SECDATA_FIRMWARE_FLAGS, | |
| VB2_SECDATA_FIRMWARE_FLAG_DEV_MODE); | |
| sd->status &= ~VB2_SD_STATUS_SECDATA_FIRMWARE_INIT; | |
| TEST_SUCC(vb2_check_dev_switch(ctx), "secdata_firmware fail normal"); | |
| TEST_EQ(sd->flags & VB2_SD_FLAG_DEV_MODE_ENABLED, 0, " sd not in dev"); | |
| TEST_EQ(ctx->flags & VB2_CONTEXT_DEVELOPER_MODE, 0, " ctx not in dev"); | |
| /* secdata_firmware failure in recovery mode continues */ | |
| reset_common_data(); | |
| ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; | |
| sd->status &= ~VB2_SD_STATUS_SECDATA_FIRMWARE_INIT; | |
| TEST_SUCC(vb2_check_dev_switch(ctx), "secdata_firmware fail recovery"); | |
| TEST_EQ(sd->flags & VB2_SD_FLAG_DEV_MODE_ENABLED, 0, " sd not in dev"); | |
| TEST_EQ(ctx->flags & VB2_CONTEXT_DEVELOPER_MODE, 0, " ctx not in dev"); | |
| /* And doesn't check or clear dev disable request */ | |
| reset_common_data(); | |
| ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; | |
| sd->status &= ~VB2_SD_STATUS_SECDATA_FIRMWARE_INIT; | |
| vb2_nv_set(ctx, VB2_NV_DISABLE_DEV_REQUEST, 1); | |
| TEST_SUCC(vb2_check_dev_switch(ctx), | |
| "secdata_firmware fail recovery disable"); | |
| TEST_EQ(sd->flags & VB2_SD_FLAG_DEV_MODE_ENABLED, 0, " sd not in dev"); | |
| TEST_EQ(ctx->flags & VB2_CONTEXT_DEVELOPER_MODE, 0, " ctx not in dev"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_DISABLE_DEV_REQUEST), | |
| 1, " request not cleared"); | |
| /* Can still override with GBB flag */ | |
| reset_common_data(); | |
| ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; | |
| sd->status &= ~VB2_SD_STATUS_SECDATA_FIRMWARE_INIT; | |
| gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON; | |
| TEST_SUCC(vb2_check_dev_switch(ctx), | |
| "secdata_firmware fail recovery gbb"); | |
| TEST_NEQ(sd->flags & VB2_SD_FLAG_DEV_MODE_ENABLED, 0, " sd in dev"); | |
| TEST_NEQ(ctx->flags & VB2_CONTEXT_DEVELOPER_MODE, 0, " ctx in dev"); | |
| TEST_EQ(mock_tpm_clear_called, 1, " tpm clear"); | |
| /* Force wipeout by ctx flag */ | |
| reset_common_data(); | |
| ctx->flags |= VB2_CONTEXT_FORCE_WIPEOUT_MODE; | |
| TEST_SUCC(vb2_check_dev_switch(ctx), "wipeout on ctx flag"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_REQ_WIPEOUT), 1, " nv wipeout"); | |
| } | |
| static void enable_dev_tests(void) | |
| { | |
| reset_common_data(); | |
| TEST_FAIL(vb2api_enable_developer_mode(ctx), | |
| "vb2api_enable_developer_mode - failed"); | |
| TEST_EQ(vb2_secdata_firmware_get(ctx, VB2_SECDATA_FIRMWARE_FLAGS) & | |
| VB2_SECDATA_FIRMWARE_FLAG_DEV_MODE, 0, | |
| " dev mode flag not set"); | |
| reset_common_data(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, | |
| VB2_RECOVERY_RO_MANUAL); | |
| TEST_SUCC(vb2api_enable_developer_mode(ctx), | |
| "vb2api_enable_developer_mode - success"); | |
| TEST_NEQ(vb2_secdata_firmware_get(ctx, VB2_SECDATA_FIRMWARE_FLAGS) & | |
| VB2_SECDATA_FIRMWARE_FLAG_DEV_MODE, 0, | |
| " dev mode flag set"); | |
| /* secdata_firmware not initialized, aborts */ | |
| reset_common_data(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, | |
| VB2_RECOVERY_RO_MANUAL); | |
| sd->status &= ~VB2_SD_STATUS_SECDATA_FIRMWARE_INIT; | |
| sd->status |= VB2_SD_STATUS_RECOVERY_DECIDED; | |
| TEST_SUCC(vb2api_enable_developer_mode(ctx), | |
| "secdata_firmware no init, enable dev mode ignored"); | |
| sd->status |= VB2_SD_STATUS_SECDATA_FIRMWARE_INIT; | |
| TEST_EQ(vb2_secdata_firmware_get(ctx, VB2_SECDATA_FIRMWARE_FLAGS) & | |
| VB2_SECDATA_FIRMWARE_FLAG_DEV_MODE, 0, | |
| " dev mode flag not set"); | |
| } | |
| static void tpm_clear_tests(void) | |
| { | |
| /* No clear request */ | |
| reset_common_data(); | |
| TEST_SUCC(vb2_check_tpm_clear(ctx), "no clear request"); | |
| TEST_EQ(mock_tpm_clear_called, 0, "tpm not cleared"); | |
| /* Successful request */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_CLEAR_TPM_OWNER_REQUEST, 1); | |
| TEST_SUCC(vb2_check_tpm_clear(ctx), "clear request"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_CLEAR_TPM_OWNER_REQUEST), | |
| 0, "request cleared"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_CLEAR_TPM_OWNER_DONE), | |
| 1, "done set"); | |
| TEST_EQ(mock_tpm_clear_called, 1, "tpm cleared"); | |
| /* Failed request */ | |
| reset_common_data(); | |
| mock_tpm_clear_retval = VB2_ERROR_EX_TPM_CLEAR_OWNER; | |
| vb2_nv_set(ctx, VB2_NV_CLEAR_TPM_OWNER_REQUEST, 1); | |
| TEST_EQ(vb2_check_tpm_clear(ctx), | |
| VB2_ERROR_EX_TPM_CLEAR_OWNER, "clear failure"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_CLEAR_TPM_OWNER_REQUEST), | |
| 0, "request cleared"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_CLEAR_TPM_OWNER_DONE), | |
| 0, "done not set"); | |
| } | |
| static void select_slot_tests(void) | |
| { | |
| /* Slot A */ | |
| reset_common_data(); | |
| TEST_SUCC(vb2_select_fw_slot(ctx), "select slot A"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_RESULT), | |
| VB2_FW_RESULT_UNKNOWN, "result unknown"); | |
| TEST_NEQ(sd->status & VB2_SD_STATUS_CHOSE_SLOT, 0, "chose slot"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_TRIED), 0, "tried A"); | |
| TEST_EQ(sd->fw_slot, 0, "selected A"); | |
| TEST_EQ(ctx->flags & VB2_CONTEXT_FW_SLOT_B, 0, "didn't choose B"); | |
| /* Slot B */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_TRY_NEXT, 1); | |
| TEST_SUCC(vb2_select_fw_slot(ctx), "select slot B"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_RESULT), | |
| VB2_FW_RESULT_UNKNOWN, "result unknown"); | |
| TEST_NEQ(sd->status & VB2_SD_STATUS_CHOSE_SLOT, 0, "chose slot"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_TRIED), 1, "tried B"); | |
| TEST_EQ(sd->fw_slot, 1, "selected B"); | |
| TEST_NEQ(ctx->flags & VB2_CONTEXT_FW_SLOT_B, 0, "ctx says choose B"); | |
| /* Slot A ran out of tries */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_FW_RESULT, VB2_FW_RESULT_TRYING); | |
| TEST_SUCC(vb2_select_fw_slot(ctx), "select slot A out of tries"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_TRY_NEXT), 1, "try B next"); | |
| TEST_NEQ(sd->status & VB2_SD_STATUS_CHOSE_SLOT, 0, "chose slot"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_TRIED), 1, "tried B"); | |
| TEST_EQ(sd->fw_slot, 1, "selected B"); | |
| TEST_NEQ(ctx->flags & VB2_CONTEXT_FW_SLOT_B, 0, "ctx says choose B"); | |
| /* Slot A ran out of tries, but slot B not present */ | |
| reset_common_data(); | |
| ctx->flags |= VB2_CONTEXT_SLOT_A_ONLY; | |
| vb2_nv_set(ctx, VB2_NV_FW_RESULT, VB2_FW_RESULT_TRYING); | |
| TEST_EQ(vb2_select_fw_slot(ctx), VB2_ERROR_API_NEXT_SLOT_UNAVAILABLE, | |
| "don't try slot B if only one slot present"); | |
| TEST_EQ(sd->status & VB2_SD_STATUS_CHOSE_SLOT, 0, "didn't choose slot"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_TRIED), 0, "tried A"); | |
| TEST_EQ(sd->fw_slot, 0, "selected A"); | |
| TEST_EQ(ctx->flags & VB2_CONTEXT_FW_SLOT_B, 0, "didn't choose B"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_TRY_NEXT), 0, "didn't try B next"); | |
| /* Slot A ran out of tries, even with nofail active */ | |
| reset_common_data(); | |
| ctx->flags |= VB2_CONTEXT_NOFAIL_BOOT; | |
| vb2_nv_set(ctx, VB2_NV_FW_RESULT, VB2_FW_RESULT_TRYING); | |
| TEST_SUCC(vb2_select_fw_slot(ctx), "select slot A out of tries"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_TRY_NEXT), 1, "try B next"); | |
| TEST_NEQ(sd->status & VB2_SD_STATUS_CHOSE_SLOT, 0, "chose slot"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_TRIED), 1, "tried B"); | |
| TEST_EQ(sd->fw_slot, 1, "selected B"); | |
| TEST_NEQ(ctx->flags & VB2_CONTEXT_FW_SLOT_B, 0, "ctx says choose B"); | |
| /* Slot A used up a try */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_TRY_COUNT, 3); | |
| TEST_SUCC(vb2_select_fw_slot(ctx), "try slot A"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_RESULT), | |
| VB2_FW_RESULT_TRYING, "result trying"); | |
| TEST_NEQ(sd->status & VB2_SD_STATUS_CHOSE_SLOT, 0, "chose slot"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_TRIED), 0, "tried A"); | |
| TEST_EQ(sd->fw_slot, 0, "selected A"); | |
| TEST_EQ(ctx->flags & VB2_CONTEXT_FW_SLOT_B, 0, "didn't choose B"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_TRY_COUNT), 2, "tries decremented"); | |
| /* Slot A failed, but nofail active */ | |
| reset_common_data(); | |
| ctx->flags |= VB2_CONTEXT_NOFAIL_BOOT; | |
| vb2_nv_set(ctx, VB2_NV_TRY_COUNT, 3); | |
| TEST_SUCC(vb2_select_fw_slot(ctx), "try slot A"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_RESULT), | |
| VB2_FW_RESULT_TRYING, "result trying"); | |
| TEST_NEQ(sd->status & VB2_SD_STATUS_CHOSE_SLOT, 0, "chose slot"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_TRIED), 0, "tried A"); | |
| TEST_EQ(sd->fw_slot, 0, "selected A"); | |
| TEST_EQ(ctx->flags & VB2_CONTEXT_FW_SLOT_B, 0, "didn't choose B"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_TRY_COUNT), 3, "tries not decremented"); | |
| /* Tried/result get copied to the previous fields */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_FW_TRIED, 0); | |
| vb2_nv_set(ctx, VB2_NV_FW_RESULT, VB2_FW_RESULT_SUCCESS); | |
| vb2_select_fw_slot(ctx); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_PREV_TRIED), 0, "prev A"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_PREV_RESULT), VB2_FW_RESULT_SUCCESS, | |
| "prev success"); | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_FW_TRIED, 1); | |
| vb2_nv_set(ctx, VB2_NV_FW_RESULT, VB2_FW_RESULT_FAILURE); | |
| vb2_select_fw_slot(ctx); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_PREV_TRIED), 1, "prev B"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_FW_PREV_RESULT), VB2_FW_RESULT_FAILURE, | |
| "prev failure"); | |
| } | |
| static void need_reboot_for_display_tests(void) | |
| { | |
| /* Display not available, reboot required */ | |
| reset_common_data(); | |
| TEST_EQ(vb2api_need_reboot_for_display(ctx), 1, | |
| "need_reboot_for_display: need reboot"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_DISPLAY_REQUEST), 1, | |
| " set display request"); | |
| /* Display available, don't need reboot */ | |
| reset_common_data(); | |
| sd->flags |= VB2_SD_FLAG_DISPLAY_AVAILABLE; | |
| TEST_EQ(vb2api_need_reboot_for_display(ctx), 0, | |
| "need_reboot_for_display: don't need reboot"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_DISPLAY_REQUEST), 0, | |
| " not set display request"); | |
| } | |
| static void clear_recovery_tests(void) | |
| { | |
| /* Manual recovery */ | |
| reset_common_data(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, 4); | |
| vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST, 5); | |
| vb2_nv_set(ctx, VB2_NV_RECOVERY_SUBCODE, 13); | |
| vb2api_clear_recovery(ctx); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST), | |
| 0, " request cleared"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_SUBCODE), | |
| 0, " subcode cleared"); | |
| /* Broken screen */ | |
| reset_common_data(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_BROKEN_SCREEN, 4); | |
| vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST, 5); | |
| vb2_nv_set(ctx, VB2_NV_RECOVERY_SUBCODE, 13); | |
| vb2api_clear_recovery(ctx); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST), | |
| 0, " request cleared"); | |
| TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_SUBCODE), | |
| 4, " subcode shifted"); | |
| } | |
| static void get_recovery_reason_tests(void) | |
| { | |
| reset_common_data(); | |
| sd->recovery_reason = 4; | |
| TEST_EQ(vb2api_get_recovery_reason(ctx), 4, "correct recovery reason"); | |
| } | |
| static void diagnostic_ui_enabled_tests(void) | |
| { | |
| reset_common_data(); | |
| vb2api_secdata_kernel_create(ctx); | |
| vb2_secdata_kernel_init(ctx); | |
| TEST_EQ(vb2api_diagnostic_ui_enabled(ctx), 1, | |
| "diagnostic UI enabled"); | |
| reset_common_data(); | |
| vb2api_secdata_kernel_create(ctx); | |
| vb2_secdata_kernel_init(ctx); | |
| vb2_secdata_kernel_set( | |
| ctx, VB2_SECDATA_KERNEL_FLAGS, | |
| VB2_SECDATA_KERNEL_FLAG_DIAGNOSTIC_UI_DISABLED); | |
| TEST_EQ(vb2api_diagnostic_ui_enabled(ctx), 0, | |
| "diagnostic UI disabled"); | |
| } | |
| static void dev_default_boot_tests(void) | |
| { | |
| /* No default boot */ | |
| reset_common_data(); | |
| TEST_EQ(vb2api_get_dev_default_boot_target(ctx), | |
| VB2_DEV_DEFAULT_BOOT_TARGET_INTERNAL, | |
| "no default boot, boot disk"); | |
| /* Set boot altfw by GBB */ | |
| reset_common_data(); | |
| gbb.flags |= VB2_GBB_FLAG_DEFAULT_DEV_BOOT_ALTFW; | |
| vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT, | |
| VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL); | |
| TEST_EQ(vb2api_get_dev_default_boot_target(ctx), | |
| VB2_DEV_DEFAULT_BOOT_TARGET_ALTFW, | |
| "GBB set default boot altfw"); | |
| /* Boot from internal disk */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT, | |
| VB2_DEV_DEFAULT_BOOT_TARGET_INTERNAL); | |
| TEST_EQ(vb2api_get_dev_default_boot_target(ctx), | |
| VB2_DEV_DEFAULT_BOOT_TARGET_INTERNAL, | |
| "set default boot internal disk"); | |
| /* Boot from external disk */ | |
| reset_common_data(); | |
| ctx->flags |= VB2_CONTEXT_DEV_BOOT_EXTERNAL_ALLOWED; | |
| vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT, | |
| VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL); | |
| TEST_EQ(vb2api_get_dev_default_boot_target(ctx), | |
| VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL, | |
| "set default boot external disk"); | |
| /* Boot from external disk not allowed */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT, | |
| VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL); | |
| TEST_EQ(vb2api_get_dev_default_boot_target(ctx), | |
| VB2_DEV_DEFAULT_BOOT_TARGET_INTERNAL, | |
| "default boot external not allowed"); | |
| reset_common_data(); | |
| ctx->flags |= VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED; | |
| vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT, | |
| VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL); | |
| TEST_EQ(vb2api_get_dev_default_boot_target(ctx), | |
| VB2_DEV_DEFAULT_BOOT_TARGET_INTERNAL, | |
| "default boot external not allowed"); | |
| /* Boot altfw */ | |
| reset_common_data(); | |
| ctx->flags |= VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED; | |
| vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT, | |
| VB2_DEV_DEFAULT_BOOT_TARGET_ALTFW); | |
| TEST_EQ(vb2api_get_dev_default_boot_target(ctx), | |
| VB2_DEV_DEFAULT_BOOT_TARGET_ALTFW, | |
| "set default boot altfw"); | |
| /* Boot altfw not allowed */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT, | |
| VB2_DEV_DEFAULT_BOOT_TARGET_ALTFW); | |
| TEST_EQ(vb2api_get_dev_default_boot_target(ctx), | |
| VB2_DEV_DEFAULT_BOOT_TARGET_INTERNAL, | |
| "default boot altfw not allowed"); | |
| reset_common_data(); | |
| ctx->flags |= VB2_CONTEXT_DEV_BOOT_EXTERNAL_ALLOWED; | |
| vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT, | |
| VB2_DEV_DEFAULT_BOOT_TARGET_ALTFW); | |
| TEST_EQ(vb2api_get_dev_default_boot_target(ctx), | |
| VB2_DEV_DEFAULT_BOOT_TARGET_INTERNAL, | |
| "default boot altfw not allowed"); | |
| } | |
| static void fill_dev_boot_flags_tests(void) | |
| { | |
| /* Dev boot - allowed by default */ | |
| reset_common_data(); | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_ALLOWED, | |
| "dev boot - allowed by default"); | |
| /* Dev boot - disabled by FWMP */ | |
| reset_common_data(); | |
| fwmp->flags |= VB2_SECDATA_FWMP_DEV_DISABLE_BOOT; | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_FALSE(ctx->flags & VB2_CONTEXT_DEV_BOOT_ALLOWED, | |
| "dev boot - FWMP disabled"); | |
| /* Dev boot - force enabled by GBB */ | |
| reset_common_data(); | |
| fwmp->flags |= VB2_SECDATA_FWMP_DEV_DISABLE_BOOT; | |
| gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON; | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_ALLOWED, | |
| "dev boot - GBB force dev on"); | |
| /* External boot - not allowed by default */ | |
| reset_common_data(); | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_FALSE(ctx->flags & VB2_CONTEXT_DEV_BOOT_EXTERNAL_ALLOWED, | |
| "dev boot external - not allowed by default"); | |
| /* External boot - enabled by nvdata */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_DEV_BOOT_EXTERNAL, 1); | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_EXTERNAL_ALLOWED, | |
| "dev boot external - nvdata enabled"); | |
| /* External boot - enabled by FWMP */ | |
| reset_common_data(); | |
| fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_EXTERNAL; | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_EXTERNAL_ALLOWED, | |
| "dev boot external - secdata enabled"); | |
| /* External boot - force enabled by GBB */ | |
| reset_common_data(); | |
| gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_BOOT_USB; | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_EXTERNAL_ALLOWED, | |
| "dev boot external - GBB force enabled"); | |
| /* External boot - set all flags */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_DEV_BOOT_EXTERNAL, 1); | |
| fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_EXTERNAL; | |
| gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_BOOT_USB; | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_EXTERNAL_ALLOWED, | |
| "dev boot external - all flags set"); | |
| /* Alternate boot - not allowed by default */ | |
| reset_common_data(); | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_FALSE(ctx->flags & VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED, | |
| "dev boot altfw - not allowed by default"); | |
| /* Alternate boot - enabled by nvdata */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_DEV_BOOT_ALTFW, 1); | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED, | |
| "dev boot altfw - nvdata enabled"); | |
| /* Alternate boot - enabled by FWMP */ | |
| reset_common_data(); | |
| fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_ALTFW; | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED, | |
| "dev boot altfw - secdata enabled"); | |
| /* Alternate boot - force enabled by GBB */ | |
| reset_common_data(); | |
| gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_BOOT_ALTFW; | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED, | |
| "dev boot altfw - GBB force enabled"); | |
| /* Alternate boot - set all flags */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_DEV_BOOT_ALTFW, 1); | |
| fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_ALTFW; | |
| gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_BOOT_ALTFW; | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED, | |
| "dev boot altfw - all flags set"); | |
| /* Dev boot - disabled by OEM lock */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_OEM_LOCK, 1); | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_FALSE(ctx->flags & VB2_CONTEXT_DEV_BOOT_ALLOWED, | |
| "dev boot - OEM lock disabled"); | |
| /* Dev boot - force enabled by GBB with OEM lock */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_OEM_LOCK, 1); | |
| gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON; | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_ALLOWED, | |
| "dev boot - GBB force dev on with OEM lock"); | |
| /* Fastboot - allowed in dev by GBB flag */ | |
| reset_common_data(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| gbb.flags |= VB2_GBB_FLAG_FORCE_UNLOCK_FASTBOOT; | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_TRUE(ctx->flags & VB2_CONTEXT_FASTBOOT_ALLOWED, | |
| "fastboot allowed - dev mode + GBB flag"); | |
| /* Fastboot - allowed in dev by OEM unlock and fastboot enabled */ | |
| reset_common_data(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| vb2_nv_set(ctx, VB2_NV_OEM_LOCK, 0); | |
| vb2_nv_set(ctx, VB2_NV_DEV_ENABLE_FASTBOOT, 1); | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_TRUE(ctx->flags & VB2_CONTEXT_FASTBOOT_ALLOWED, | |
| "fastboot allowed - dev mode + OEM unlock + fastboot en"); | |
| /* Fastboot - allowed in dev by GBB flag with OEM lock */ | |
| reset_common_data(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| gbb.flags |= VB2_GBB_FLAG_FORCE_UNLOCK_FASTBOOT; | |
| gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON; | |
| vb2_nv_set(ctx, VB2_NV_OEM_LOCK, 1); | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_TRUE(ctx->flags & VB2_CONTEXT_FASTBOOT_ALLOWED, | |
| "fastboot allowed - dev mode + GBB flag + OEM lock + force dev"); | |
| /* Fastboot - allowed in dev by GBB flag with fastboot disabled */ | |
| reset_common_data(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| gbb.flags |= VB2_GBB_FLAG_FORCE_UNLOCK_FASTBOOT; | |
| gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON; | |
| vb2_nv_set(ctx, VB2_NV_DEV_ENABLE_FASTBOOT, 0); | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_TRUE(ctx->flags & VB2_CONTEXT_FASTBOOT_ALLOWED, | |
| "fastboot allowed - dev mode + GBB flag + fastboot dis + force dev"); | |
| /* Fastboot - not allowed in dev with OEM lock, fastboot enabled and no GBB flag */ | |
| reset_common_data(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| vb2_nv_set(ctx, VB2_NV_OEM_LOCK, 1); | |
| vb2_nv_set(ctx, VB2_NV_DEV_ENABLE_FASTBOOT, 1); | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_FALSE(ctx->flags & VB2_CONTEXT_FASTBOOT_ALLOWED, | |
| "fastboot not allowed - dev mode + OEM lock + fastboot en + no GBB flag"); | |
| /* Fastboot - not allowed in dev with OEM unlock, fastboot disabled and no GBB flag */ | |
| reset_common_data(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_FALSE(ctx->flags & VB2_CONTEXT_FASTBOOT_ALLOWED, | |
| "fastboot not allowed - dev mode + OEM unlock + fastboot dis + no GBB flag"); | |
| /* Fastboot - not allowed in dev when DEV_BOOT_ALLOWED is disabled */ | |
| reset_common_data(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER); | |
| fwmp->flags |= VB2_SECDATA_FWMP_DEV_DISABLE_BOOT; | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_FALSE(ctx->flags & VB2_CONTEXT_FASTBOOT_ALLOWED, | |
| "fastboot not allowed - dev mode + FWMP disable boot"); | |
| /* Fastboot - allowed in manual recovery by GBB flag */ | |
| reset_common_data(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, VB2_RECOVERY_RO_MANUAL); | |
| gbb.flags |= VB2_GBB_FLAG_FORCE_UNLOCK_FASTBOOT; | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_TRUE(ctx->flags & VB2_CONTEXT_FASTBOOT_ALLOWED, | |
| "fastboot allowed - manual recovery + GBB flag"); | |
| /* Fastboot - not allowed in manual recovery with OEM unlock but no GBB flag */ | |
| reset_common_data(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_MANUAL_RECOVERY, VB2_RECOVERY_RO_MANUAL); | |
| vb2_nv_set(ctx, VB2_NV_OEM_LOCK, 0); | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_FALSE(ctx->flags & VB2_CONTEXT_FASTBOOT_ALLOWED, | |
| "fastboot not allowed - manual recovery + OEM unlock + no GBB flag"); | |
| /* Fastboot - allowed in normal mode by GBB flag */ | |
| reset_common_data(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_NORMAL); | |
| gbb.flags |= VB2_GBB_FLAG_FORCE_UNLOCK_FASTBOOT; | |
| vb2_nv_set(ctx, VB2_NV_OEM_LOCK, 0); | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_TRUE(ctx->flags & VB2_CONTEXT_FASTBOOT_ALLOWED, | |
| "fastboot allowed - normal mode + GBB flag"); | |
| /* Fastboot - not allowed in normal mode by OEM Lock and not GBB flag */ | |
| reset_common_data(); | |
| SET_BOOT_MODE(ctx, VB2_BOOT_MODE_NORMAL); | |
| vb2_nv_set(ctx, VB2_NV_OEM_LOCK, 1); | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_FALSE(ctx->flags & VB2_CONTEXT_FASTBOOT_ALLOWED, | |
| "fastboot not allowed - normal mode + OEM lock + no GBB flag"); | |
| /* OEM Lock - enabled if non-zero */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_OEM_LOCK, 1); | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_TRUE(ctx->flags & VB2_CONTEXT_OEM_LOCK_ENABLED, | |
| "OEM Lock enabled - OEM Lock"); | |
| /* OEM Lock - disabled if zero */ | |
| reset_common_data(); | |
| vb2_nv_set(ctx, VB2_NV_OEM_LOCK, 0); | |
| vb2_fill_dev_boot_flags(ctx); | |
| TEST_FALSE(ctx->flags & VB2_CONTEXT_OEM_LOCK_ENABLED, | |
| "OEM Lock disabled - OEM unlock"); | |
| } | |
| int main(int argc, char* argv[]) | |
| { | |
| init_workbuf_tests(); | |
| misc_tests(); | |
| gbb_tests(); | |
| fail_tests(); | |
| previous_boot_fail_tests(); | |
| recovery_tests(); | |
| dev_switch_tests(); | |
| enable_dev_tests(); | |
| tpm_clear_tests(); | |
| select_slot_tests(); | |
| need_reboot_for_display_tests(); | |
| clear_recovery_tests(); | |
| get_recovery_reason_tests(); | |
| diagnostic_ui_enabled_tests(); | |
| dev_default_boot_tests(); | |
| fill_dev_boot_flags_tests(); | |
| return gTestSuccess ? 0 : 255; | |
| } |