summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2012-01-25 14:06:24 -0800
committerStefan Reinauer <reinauer@chromium.org>2012-01-25 15:12:09 -0800
commitbf020a0d4db68897058503767067567565450dde (patch)
tree2708dc94eb04c8aaa6f14beda2e61aec6742c20b
parent5fd35971de5e9fe2a7988519dc8d13ea3af0c0c5 (diff)
downloadvboot-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.c9
-rw-r--r--tests/Makefile3
-rw-r--r--tests/vboot_api_kernel_tests.c320
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;
+}