diff options
author | Bill Richardson <wfrichar@chromium.org> | 2012-01-25 14:06:24 -0800 |
---|---|---|
committer | Stefan Reinauer <reinauer@chromium.org> | 2012-01-25 15:12:09 -0800 |
commit | bf020a0d4db68897058503767067567565450dde (patch) | |
tree | 2708dc94eb04c8aaa6f14beda2e61aec6742c20b | |
parent | 5fd35971de5e9fe2a7988519dc8d13ea3af0c0c5 (diff) | |
download | vboot-bf020a0d4db68897058503767067567565450dde.tar.gz |
Make VbTryLoadKernel() go to recovery when no valid disks are found
Previously, it was going to recovery only when no disks existed. That didn't
catch the case where disks exist but none of them are usable.
BUG=chrome-os-partner:7715
TEST=manual
I've added a test specifically for this, so just
make
make runtests
should verify it.
To test on actual hardware, find a disk or USB drive that has something
other than 512 bytes per LBA, and try it. It won't be bootable, but using it
shouldn't hang the system or cause weird behavior.
Once in recovery, press TAB, and you should see the reason code
VBNV_RECOVERY_RW_NO_DISK
Change-Id: I475ddd01e13fa806025a2107c260c030d098a17e
Reviewed-on: https://gerrit.chromium.org/gerrit/14816
Tested-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-by: Stefan Reinauer <reinauer@chromium.org>
Commit-Ready: Bill Richardson <wfrichar@chromium.org>
-rw-r--r-- | firmware/lib/vboot_api_kernel.c | 9 | ||||
-rw-r--r-- | tests/Makefile | 3 | ||||
-rw-r--r-- | tests/vboot_api_kernel_tests.c | 320 |
3 files changed, 329 insertions, 3 deletions
diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c index 8ed22cbf..bcb3d232 100644 --- a/firmware/lib/vboot_api_kernel.c +++ b/firmware/lib/vboot_api_kernel.c @@ -75,7 +75,9 @@ uint32_t VbTryLoadKernel(VbCommonParams* cparams, LoadKernelParams* p, if (512 != disk_info[i].bytes_per_lba || /* cgptlib restriction */ 32 > disk_info[i].lba_count || /* ditto */ get_info_flags != disk_info[i].flags) { /* got only what we asked for */ - VBDEBUG((" skipping - bogus parameters\n")); + VBDEBUG((" skipping: bytes_per_lba=%Ld lba_count=%Ld flags=0x%x\n", + disk_info[i].bytes_per_lba, disk_info[i].lba_count, + disk_info[i].flags)); continue; } p->disk_handle = disk_info[i].handle; @@ -92,8 +94,11 @@ uint32_t VbTryLoadKernel(VbCommonParams* cparams, LoadKernelParams* p, } /* If we didn't succeed, don't return a disk handle */ - if (VBERROR_SUCCESS != retval) + if (VBERROR_SUCCESS != retval) { + VbSetRecoveryRequest(VBNV_RECOVERY_RW_NO_DISK); + retval = VBERROR_NO_DISK_FOUND; p->disk_handle = NULL; + } VbExDiskFreeInfo(disk_info, p->disk_handle); diff --git a/tests/Makefile b/tests/Makefile index 20c19dd4..9fcb5c76 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -29,7 +29,8 @@ TEST_NAMES = cgptlib_test \ vboot_firmware_tests \ vboot_nvstorage_test \ vboot_api_devmode_tests \ - vboot_audio_tests + vboot_audio_tests \ + vboot_api_kernel_tests TEST_BINS = $(addprefix ${BUILD_ROOT}/,$(TEST_NAMES)) diff --git a/tests/vboot_api_kernel_tests.c b/tests/vboot_api_kernel_tests.c new file mode 100644 index 00000000..9fe2991d --- /dev/null +++ b/tests/vboot_api_kernel_tests.c @@ -0,0 +1,320 @@ +/* Copyright (c) 2012 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 <stdio.h> +#include <stdlib.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" + + +#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]; + + /* 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 = { + {512, 10, VB_DISK_FLAG_REMOVABLE, 0 }, /* too small */ + {2048, 100, VB_DISK_FLAG_REMOVABLE, 0 }, /* wrong LBA */ + {512, 100, VB_DISK_FLAG_FIXED, 0 }, /* wrong type */ + {512, 100, 0, 0 }, /* wrong flags */ + {512, 100, -1, 0 }, /* still wrong flags */ + {512, 100, VB_DISK_FLAG_REMOVABLE, pickme}, + {512, 100, VB_DISK_FLAG_REMOVABLE, "holygrail"}, /* already got one */ + }, + .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 = "second removable drive", + .want_flags = VB_DISK_FLAG_REMOVABLE, + .disks_to_provide = { + {512, 100, 0, 0 }, /* wrong flags */ + {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 = { + {512, 10, VB_DISK_FLAG_FIXED, 0 }, /* too small */ + {2048, 100, VB_DISK_FLAG_FIXED, 0 }, /* wrong LBA */ + {512, 100, VB_DISK_FLAG_REMOVABLE, 0 }, /* wrong type */ + {512, 100, 0, 0 }, /* wrong flags */ + {512, 100, -1, 0 }, /* still wrong flags */ + {512, 100, VB_DISK_FLAG_REMOVABLE|VB_DISK_FLAG_FIXED, 0 }, /* flags */ + {512, 100, VB_DISK_FLAG_FIXED, pickme}, + {512, 100, VB_DISK_FLAG_FIXED, "holygrail"}, /* already got one */ + }, + .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 = { + {512, 10, VB_DISK_FLAG_FIXED, 0 }, /* too small */ + {2048, 100, VB_DISK_FLAG_FIXED, 0 }, /* wrong LBA */ + {512, 100, VB_DISK_FLAG_REMOVABLE, 0 }, /* wrong type */ + {512, 100, 0, 0 }, /* wrong flags */ + {512, 100, -1, 0 }, /* still wrong flags */ + {512, 100, VB_DISK_FLAG_FIXED, "bad1"}, /* doesn't load */ + {512, 100, VB_DISK_FLAG_FIXED, "bad2"}, /* doesn't load */ + }, + .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 = DONT_CARE, + .expected_to_load_disk = 0, + .expected_return_val = VBERROR_NO_DISK_FOUND + }, + +}; + + +/****************************************************************************/ + +/* Mock data */ +static LoadKernelParams lkparams; +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; + +/* Reset mock data (for use before each test) */ +static void ResetMocks(int i) { + Memset(&lkparams, 0, sizeof(lkparams)); + 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; +} + +int CheckResults(void) { + VBDEBUG(("%s()\n", __FUNCTION__)); + VBDEBUG((" recovery_request: %x %x\n", + t->expected_recovery_request_val, got_recovery_request_val)); + VBDEBUG((" find_disk: (%s) (%s)\n", + (t->expected_to_find_disk == DONT_CARE + ? "DONT CARE" + : t->expected_to_find_disk), + got_find_disk)); + VBDEBUG((" load_disk: (%s) (%s)\n", + (t->expected_to_load_disk == DONT_CARE + ? "DONT CARE" + : t->expected_to_load_disk), + got_load_disk)); + VBDEBUG((" return_val: %x %x\n", + t->expected_return_val, got_return_val)); + return (t->expected_recovery_request_val == got_recovery_request_val && + (t->expected_to_find_disk == DONT_CARE || + t->expected_to_find_disk == got_find_disk) && + (t->expected_to_load_disk == DONT_CARE || + t->expected_to_load_disk == got_load_disk) && + t->expected_return_val == got_return_val); +} + +/****************************************************************************/ +/* Mocked verification functions */ + +VbError_t VbExDiskGetInfo(VbDiskInfo** infos_ptr, uint32_t* count, + uint32_t disk_flags) { + int i; + int num_disks = 0; + + VBDEBUG(("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 = 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; + VBDEBUG((" mock_disk[%d] %Ld %Ld 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; + + VBDEBUG((" *count=%Ld\n", *count)); + VBDEBUG((" 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; + VBDEBUG(("%s(): got_load_disk = %s\n", __FUNCTION__, + got_load_disk ? got_load_disk : "0")); + return VBERROR_SUCCESS; +} + +VbError_t LoadKernel(LoadKernelParams* params) { + got_find_disk = (const char *)params->disk_handle; + VBDEBUG(("%s(%d): got_find_disk = %s\n", __FUNCTION__, + load_kernel_calls, + got_find_disk ? got_find_disk : "0")); + return t->loadkernel_return_val[load_kernel_calls++]; +} + +int VbNvSet(VbNvContext* context, VbNvParam param, uint32_t value) { + VBDEBUG(("%s(): got_recovery_request_val = %d (0x%x)\n", __FUNCTION__, + value, value)); + got_recovery_request_val = value; + return 0; +} + +/****************************************************************************/ + + + +/* This is not declared in any headers, so declare it here. */ +uint32_t VbTryLoadKernel(VbCommonParams* cparams, LoadKernelParams* p, + uint32_t get_info_flags); + + +static void VbTryLoadKernelTest(void) { + int i; + int num_tests = sizeof(test) / sizeof(test[0]); + + for (i=0; i<num_tests; i++) { + VBDEBUG(("STARTING %s ...\n", test[i].name)); + ResetMocks(i); + got_return_val = VbTryLoadKernel(0, &lkparams, test[i].want_flags); + VBDEBUG(("VbTryLoadKernel(): got_return_val = 0x%x\n", got_return_val)); + TEST_TRUE(CheckResults(), test[i].name); + } +} + + +/* disable MSVC warnings on unused arguments */ +__pragma(warning (disable: 4100)) + +int main(int argc, char* argv[]) { + int error_code = 0; + + VbTryLoadKernelTest(); + + if (!gTestSuccess) + error_code = 255; + + return error_code; +} |