| /* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| * | |
| * Tests for VbTryLoadKernel() | |
| */ | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include "2sysincludes.h" | |
| #include "2api.h" | |
| #include "2nvstorage.h" | |
| #include "gbb_header.h" | |
| #include "load_kernel_fw.h" | |
| #include "rollback_index.h" | |
| #include "test_common.h" | |
| #include "utility.h" | |
| #include "vboot_api.h" | |
| #include "vboot_kernel.h" | |
| struct LoadKernelParams *VbApiKernelGetParams(void); | |
| #define MAX_TEST_DISKS 10 | |
| #define DEFAULT_COUNT -1 | |
| typedef struct { | |
| uint64_t bytes_per_lba; | |
| uint64_t lba_count; | |
| uint32_t flags; | |
| const char *diskname; | |
| } disk_desc_t; | |
| typedef struct { | |
| char *name; | |
| /* inputs for test case */ | |
| uint32_t want_flags; | |
| VbError_t diskgetinfo_return_val; | |
| disk_desc_t disks_to_provide[MAX_TEST_DISKS]; | |
| int disk_count_to_return; | |
| VbError_t loadkernel_return_val[MAX_TEST_DISKS]; | |
| uint8_t external_expected[MAX_TEST_DISKS]; | |
| /* outputs from test */ | |
| uint32_t expected_recovery_request_val; | |
| const char *expected_to_find_disk; | |
| const char *expected_to_load_disk; | |
| uint32_t expected_return_val; | |
| } test_case_t; | |
| /****************************************************************************/ | |
| /* Test cases */ | |
| static const char pickme[] = "correct choice"; | |
| #define DONT_CARE ((const char *)42) | |
| test_case_t test[] = { | |
| { | |
| .name = "first removable drive", | |
| .want_flags = VB_DISK_FLAG_REMOVABLE, | |
| .disks_to_provide = { | |
| /* too small */ | |
| {512, 10, VB_DISK_FLAG_REMOVABLE, 0}, | |
| /* wrong LBA */ | |
| {2048, 100, VB_DISK_FLAG_REMOVABLE, 0}, | |
| /* wrong type */ | |
| {512, 100, VB_DISK_FLAG_FIXED, 0}, | |
| /* wrong flags */ | |
| {512, 100, 0, 0}, | |
| /* still wrong flags */ | |
| {512, 100, -1, 0}, | |
| {512, 100, | |
| VB_DISK_FLAG_REMOVABLE | VB_DISK_FLAG_EXTERNAL_GPT, | |
| pickme}, | |
| /* already got one */ | |
| {512, 100, VB_DISK_FLAG_REMOVABLE, "holygrail"}, | |
| }, | |
| .disk_count_to_return = DEFAULT_COUNT, | |
| .diskgetinfo_return_val = VBERROR_SUCCESS, | |
| .loadkernel_return_val = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1,}, | |
| .external_expected = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, | |
| .expected_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED, | |
| .expected_to_find_disk = pickme, | |
| .expected_to_load_disk = pickme, | |
| .expected_return_val = VBERROR_SUCCESS | |
| }, | |
| { | |
| .name = "second removable drive", | |
| .want_flags = VB_DISK_FLAG_REMOVABLE, | |
| .disks_to_provide = { | |
| /* wrong flags */ | |
| {512, 100, 0, 0}, | |
| {512, 100, VB_DISK_FLAG_REMOVABLE, "not yet"}, | |
| {512, 100, VB_DISK_FLAG_REMOVABLE, pickme}, | |
| }, | |
| .disk_count_to_return = DEFAULT_COUNT, | |
| .diskgetinfo_return_val = VBERROR_SUCCESS, | |
| .loadkernel_return_val = {1, 0, 1, 1, 1, 1, 1, 1, 1, 1,}, | |
| .expected_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED, | |
| .expected_to_find_disk = pickme, | |
| .expected_to_load_disk = pickme, | |
| .expected_return_val = VBERROR_SUCCESS | |
| }, | |
| { | |
| .name = "first fixed drive", | |
| .want_flags = VB_DISK_FLAG_FIXED, | |
| .disks_to_provide = { | |
| /* too small */ | |
| {512, 10, VB_DISK_FLAG_FIXED, 0}, | |
| /* wrong LBA */ | |
| {2048, 100, VB_DISK_FLAG_FIXED, 0}, | |
| /* wrong type */ | |
| {512, 100, VB_DISK_FLAG_REMOVABLE, 0}, | |
| /* wrong flags */ | |
| {512, 100, 0, 0}, | |
| /* still wrong flags */ | |
| {512, 100, -1, 0}, | |
| /* flags */ | |
| {512, 100, VB_DISK_FLAG_REMOVABLE|VB_DISK_FLAG_FIXED, | |
| 0}, | |
| {512, 100, VB_DISK_FLAG_FIXED, pickme}, | |
| /* already got one */ | |
| {512, 100, VB_DISK_FLAG_FIXED, "holygrail"}, | |
| }, | |
| .disk_count_to_return = DEFAULT_COUNT, | |
| .diskgetinfo_return_val = VBERROR_SUCCESS, | |
| .loadkernel_return_val = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1,}, | |
| .expected_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED, | |
| .expected_to_find_disk = pickme, | |
| .expected_to_load_disk = pickme, | |
| .expected_return_val = VBERROR_SUCCESS | |
| }, | |
| { | |
| .name = "no drives at all", | |
| .want_flags = VB_DISK_FLAG_FIXED, | |
| .disks_to_provide = {}, | |
| .disk_count_to_return = DEFAULT_COUNT, | |
| .diskgetinfo_return_val = VBERROR_SUCCESS, | |
| .loadkernel_return_val = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1,}, | |
| .expected_recovery_request_val = VBNV_RECOVERY_RW_NO_DISK, | |
| .expected_to_find_disk = 0, | |
| .expected_to_load_disk = 0, | |
| .expected_return_val = VBERROR_NO_DISK_FOUND | |
| }, | |
| { | |
| .name = "no valid drives", | |
| .want_flags = VB_DISK_FLAG_FIXED, | |
| .disks_to_provide = { | |
| /* too small */ | |
| {512, 10, VB_DISK_FLAG_FIXED, 0}, | |
| /* wrong LBA */ | |
| {2048, 100, VB_DISK_FLAG_FIXED, 0}, | |
| /* wrong type */ | |
| {512, 100, VB_DISK_FLAG_REMOVABLE, 0}, | |
| /* wrong flags */ | |
| {512, 100, 0, 0}, | |
| /* still wrong flags */ | |
| {512, 100, -1, 0}, | |
| /* doesn't load */ | |
| {512, 100, VB_DISK_FLAG_FIXED, "bad1"}, | |
| /* doesn't load */ | |
| {512, 100, VB_DISK_FLAG_FIXED, "bad2"}, | |
| }, | |
| .disk_count_to_return = DEFAULT_COUNT, | |
| .diskgetinfo_return_val = VBERROR_SUCCESS, | |
| .loadkernel_return_val = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1,}, | |
| .expected_recovery_request_val = VBNV_RECOVERY_RW_NO_KERNEL, | |
| .expected_to_find_disk = DONT_CARE, | |
| .expected_to_load_disk = 0, | |
| .expected_return_val = 1 | |
| }, | |
| }; | |
| /****************************************************************************/ | |
| /* Mock data */ | |
| static VbDiskInfo mock_disks[MAX_TEST_DISKS]; | |
| static test_case_t *t; | |
| static int load_kernel_calls; | |
| static uint32_t got_recovery_request_val; | |
| static const char *got_find_disk; | |
| static const char *got_load_disk; | |
| static uint32_t got_return_val; | |
| static uint32_t got_external_mismatch; | |
| static struct vb2_context ctx; | |
| /** | |
| * Reset mock data (for use before each test) | |
| */ | |
| static void ResetMocks(int i) | |
| { | |
| memset(&ctx, 0, sizeof(ctx)); | |
| memset(VbApiKernelGetParams(), 0, sizeof(LoadKernelParams)); | |
| memset(&mock_disks, 0, sizeof(mock_disks)); | |
| load_kernel_calls = 0; | |
| got_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED; | |
| got_find_disk = 0; | |
| got_load_disk = 0; | |
| got_return_val = 0xdeadbeef; | |
| t = test + i; | |
| } | |
| int is_nonzero(const void *vptr, size_t count) | |
| { | |
| const char *p = (const char *)vptr; | |
| while (count--) | |
| if (*p++) | |
| return 1; | |
| return 0; | |
| } | |
| /****************************************************************************/ | |
| /* Mocked verification functions */ | |
| VbError_t VbExDiskGetInfo(VbDiskInfo **infos_ptr, uint32_t *count, | |
| uint32_t disk_flags) | |
| { | |
| int i; | |
| int num_disks = 0; | |
| VB2_DEBUG("My %s\n", __FUNCTION__); | |
| *infos_ptr = mock_disks; | |
| for(i = 0; i < MAX_TEST_DISKS; i++) { | |
| if (is_nonzero(&t->disks_to_provide[i], | |
| sizeof(t->disks_to_provide[i]))) { | |
| mock_disks[num_disks].bytes_per_lba = | |
| t->disks_to_provide[i].bytes_per_lba; | |
| mock_disks[num_disks].lba_count = | |
| mock_disks[num_disks].streaming_lba_count = | |
| t->disks_to_provide[i].lba_count; | |
| mock_disks[num_disks].flags = | |
| t->disks_to_provide[i].flags; | |
| mock_disks[num_disks].handle = (VbExDiskHandle_t) | |
| t->disks_to_provide[i].diskname; | |
| VB2_DEBUG(" mock_disk[%d] %" PRIu64 " %" PRIu64 | |
| " 0x%x %s\n", i, | |
| mock_disks[num_disks].bytes_per_lba, | |
| mock_disks[num_disks].lba_count, | |
| mock_disks[num_disks].flags, | |
| (mock_disks[num_disks].handle | |
| ? (char *)mock_disks[num_disks].handle | |
| : "0")); | |
| num_disks++; | |
| } else { | |
| mock_disks[num_disks].handle = | |
| (VbExDiskHandle_t)"INVALID"; | |
| } | |
| } | |
| if (t->disk_count_to_return >= 0) | |
| *count = t->disk_count_to_return; | |
| else | |
| *count = num_disks; | |
| VB2_DEBUG(" *count=%" PRIu32 "\n", *count); | |
| VB2_DEBUG(" return 0x%x\n", t->diskgetinfo_return_val); | |
| return t->diskgetinfo_return_val; | |
| } | |
| VbError_t VbExDiskFreeInfo(VbDiskInfo *infos, | |
| VbExDiskHandle_t preserve_handle) | |
| { | |
| got_load_disk = (const char *)preserve_handle; | |
| VB2_DEBUG("%s(): got_load_disk = %s\n", __FUNCTION__, | |
| got_load_disk ? got_load_disk : "0"); | |
| return VBERROR_SUCCESS; | |
| } | |
| VbError_t LoadKernel(struct vb2_context *ctx, LoadKernelParams *params, | |
| VbCommonParams *cparams) | |
| { | |
| got_find_disk = (const char *)params->disk_handle; | |
| VB2_DEBUG("%s(%d): got_find_disk = %s\n", __FUNCTION__, | |
| load_kernel_calls, | |
| got_find_disk ? got_find_disk : "0"); | |
| if (t->external_expected[load_kernel_calls] != | |
| !!(params->boot_flags & BOOT_FLAG_EXTERNAL_GPT)) | |
| got_external_mismatch++; | |
| return t->loadkernel_return_val[load_kernel_calls++]; | |
| } | |
| void vb2_nv_set(struct vb2_context *ctx, | |
| enum vb2_nv_param param, | |
| uint32_t value) | |
| { | |
| VB2_DEBUG("%s(): got_recovery_request_val = %d (0x%x)\n", __FUNCTION__, | |
| value, value); | |
| got_recovery_request_val = value; | |
| } | |
| /****************************************************************************/ | |
| static void VbTryLoadKernelTest(void) | |
| { | |
| int i; | |
| int num_tests = sizeof(test) / sizeof(test[0]); | |
| for (i = 0; i < num_tests; i++) { | |
| printf("Test case: %s ...\n", test[i].name); | |
| ResetMocks(i); | |
| TEST_EQ(VbTryLoadKernel(&ctx, 0, test[i].want_flags), | |
| t->expected_return_val, " return value"); | |
| TEST_EQ(got_recovery_request_val, | |
| t->expected_recovery_request_val, " recovery_request"); | |
| if (t->expected_to_find_disk != DONT_CARE) { | |
| TEST_PTR_EQ(got_find_disk, t->expected_to_find_disk, | |
| " find disk"); | |
| TEST_PTR_EQ(got_load_disk, t->expected_to_load_disk, | |
| " load disk"); | |
| } | |
| TEST_EQ(got_external_mismatch, 0, " external GPT errors"); | |
| } | |
| } | |
| int main(void) | |
| { | |
| VbTryLoadKernelTest(); | |
| return gTestSuccess ? 0 : 255; | |
| } |