From 49cb0d3471e768da11fe76b65769bd57dca38bd7 Mon Sep 17 00:00:00 2001 From: Randall Spangler Date: Tue, 29 Jan 2013 14:28:16 -0800 Subject: Add kernel tests BUG=chromium-os:38139 BRANCH=none TEST=make runtests Change-Id: Iee7c965d5c29063259c66d0ccb117c60f4f4a92e Signed-off-by: Randall Spangler Reviewed-on: https://gerrit.chromium.org/gerrit/42314 --- Makefile | 5 +- firmware/lib/vboot_kernel.c | 13 ++- tests/vboot_kernel_tests.c | 203 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 213 insertions(+), 8 deletions(-) create mode 100644 tests/vboot_kernel_tests.c diff --git a/Makefile b/Makefile index 6129697b..d51a18b8 100644 --- a/Makefile +++ b/Makefile @@ -425,6 +425,7 @@ TEST_NAMES = \ vboot_common3_tests \ vboot_display_tests \ vboot_firmware_tests \ + vboot_kernel_tests \ vboot_nvstorage_test # Grrr @@ -952,6 +953,7 @@ runmisctests: test_setup ${RUNTEST} ${BUILD_RUN}/tests/vboot_common3_tests ${TEST_KEYS} ${RUNTEST} ${BUILD_RUN}/tests/vboot_display_tests ${RUNTEST} ${BUILD_RUN}/tests/vboot_firmware_tests + ${RUNTEST} ${BUILD_RUN}/tests/vboot_kernel_tests ${RUNTEST} ${BUILD_RUN}/tests/vboot_nvstorage_test .PHONY: runfutiltests @@ -993,7 +995,8 @@ coverage_html: # Generate addtional coverage stats just for firmware subdir, because the # per-directory stats for the whole project don't include their own subdirs. - lcov -e ${COV_INFO}.local '${SRCDIR}/firmware/*' \ + lcov -r ${COV_INFO}.local '*/stub/*' -o ${COV_INFO}.nostub + lcov -e ${COV_INFO}.nostub '${SRCDIR}/firmware/*' \ -o ${COV_INFO}.firmware .PHONY: coverage diff --git a/firmware/lib/vboot_kernel.c b/firmware/lib/vboot_kernel.c index ec77de36..a9a6fdf3 100644 --- a/firmware/lib/vboot_kernel.c +++ b/firmware/lib/vboot_kernel.c @@ -157,8 +157,7 @@ VbError_t LoadKernel(LoadKernelParams* params) { int recovery = VBNV_RECOVERY_LK_UNSPECIFIED; /* Sanity Checks */ - if (!params || - !params->bytes_per_lba || + if (!params->bytes_per_lba || !params->ending_lba) { VBDEBUG(("LoadKernel() called with invalid params\n")); retval = VBERROR_INVALID_PARAMETER; @@ -210,27 +209,26 @@ VbError_t LoadKernel(LoadKernelParams* params) { kernel_subkey = &shared->kernel_subkey; } - do { /* Read GPT data */ gpt.sector_bytes = (uint32_t)blba; gpt.drive_sectors = params->ending_lba + 1; if (0 != AllocAndReadGptData(params->disk_handle, &gpt)) { VBDEBUG(("Unable to read GPT data\n")); shcall->check_result = VBSD_LKC_CHECK_GPT_READ_ERROR; - break; + goto bad_gpt; } /* Initialize GPT library */ if (GPT_SUCCESS != GptInit(&gpt)) { VBDEBUG(("Error parsing GPT\n")); shcall->check_result = VBSD_LKC_CHECK_GPT_PARSE_ERROR; - break; + goto bad_gpt; } /* Allocate kernel header buffers */ kbuf = (uint8_t*)VbExMalloc(KBUF_SIZE); if (!kbuf) - break; + goto bad_gpt; /* Loop over candidate kernel partitions */ while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) { @@ -516,7 +514,8 @@ VbError_t LoadKernel(LoadKernelParams* params) { } /* while(GptNextKernelEntry) */ - } while(0); + + bad_gpt: /* Free kernel buffer */ if (kbuf) diff --git a/tests/vboot_kernel_tests.c b/tests/vboot_kernel_tests.c new file mode 100644 index 00000000..0d491910 --- /dev/null +++ b/tests/vboot_kernel_tests.c @@ -0,0 +1,203 @@ +/* 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 vboot_kernel.c + */ + +#include +#include +#include + +#include "cgptlib.h" +#include "gbb_header.h" +#include "gpt.h" +#include "host_common.h" +#include "load_kernel_fw.h" +#include "test_common.h" +#include "vboot_api.h" +#include "vboot_common.h" +#include "vboot_kernel.h" +#include "vboot_nvstorage.h" + +#define LOGCALL(fmt, args...) sprintf(call_log + strlen(call_log), fmt, ##args) +#define TEST_CALLS(expect_log) TEST_STR_EQ(call_log, expect_log, " calls") + +/* Mock data */ +static char call_log[4096]; +static int disk_call_to_fail; +static int disk_calls; +static int gpt_init_fail; + +static GoogleBinaryBlockHeader gbb; +static VbExDiskHandle_t handle; +static VbNvContext vnc; +static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE]; +static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data; +static LoadKernelParams lkp; + +static void ResetCallLog(void) +{ + *call_log = 0; +} + +/** + * Reset mock data (for use before each test) + */ +static void ResetMocks(void) +{ + ResetCallLog(); + + disk_call_to_fail = 0; + disk_calls = 0; + + gpt_init_fail = 0; + + memset(&gbb, 0, sizeof(gbb)); + gbb.major_version = GBB_MAJOR_VER; + gbb.minor_version = GBB_MINOR_VER; + gbb.flags = 0; + + memset(&vnc, 0, sizeof(vnc)); + VbNvSetup(&vnc); + VbNvTeardown(&vnc); /* So CRC gets generated */ + + memset(&shared_data, 0, sizeof(shared_data)); + VbSharedDataInit(shared, sizeof(shared_data)); + + memset(&lkp, 0, sizeof(lkp)); + lkp.nv_context = &vnc; + lkp.shared_data_blob = shared; + lkp.gbb_data = &gbb; + lkp.bytes_per_lba = 512; + lkp.ending_lba = 1023; +} + +/* Mocks */ + +VbError_t VbExDiskRead(VbExDiskHandle_t handle, uint64_t lba_start, + uint64_t lba_count, void *buffer) +{ + LOGCALL("VbExDiskRead(h, %d, %d)\n", (int)lba_start, (int)lba_count); + + if (++disk_calls == disk_call_to_fail) + return VBERROR_SIMULATED; + + return VBERROR_SUCCESS; +} + +VbError_t VbExDiskWrite(VbExDiskHandle_t handle, uint64_t lba_start, + uint64_t lba_count, const void *buffer) +{ + LOGCALL("VbExDiskWrite(h, %d, %d)\n", (int)lba_start, (int)lba_count); + + if (++disk_calls == disk_call_to_fail) + return VBERROR_SIMULATED; + + return VBERROR_SUCCESS; +} + +int GptInit(GptData *gpt) +{ + return gpt_init_fail; +} + +/** + * Test reading/writing GPT + */ +static void ReadWriteGptTest(void) +{ + GptData g; + GptHeader *h; + + g.sector_bytes = 512; + g.drive_sectors = 1024; + + ResetMocks(); + TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead"); + TEST_CALLS("VbExDiskRead(h, 1, 1)\n" + "VbExDiskRead(h, 2, 32)\n" + "VbExDiskRead(h, 991, 32)\n" + "VbExDiskRead(h, 1023, 1)\n"); + ResetCallLog(); + TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree"); + TEST_CALLS(""); + + /* Data which is changed is written */ + ResetMocks(); + AllocAndReadGptData(handle, &g); + g.modified |= GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1; + ResetCallLog(); + TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 1"); + TEST_CALLS("VbExDiskWrite(h, 1, 1)\n" + "VbExDiskWrite(h, 2, 32)\n"); + + /* Data which is changed is written */ + ResetMocks(); + AllocAndReadGptData(handle, &g); + g.modified = -1; + ResetCallLog(); + TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod all"); + TEST_CALLS("VbExDiskWrite(h, 1, 1)\n" + "VbExDiskWrite(h, 2, 32)\n" + "VbExDiskWrite(h, 991, 32)\n" + "VbExDiskWrite(h, 1023, 1)\n"); + + /* If legacy signature, don't modify GPT header/entries 1 */ + ResetMocks(); + AllocAndReadGptData(handle, &g); + h = (GptHeader *)g.primary_header; + memcpy(h->signature, GPT_HEADER_SIGNATURE2, GPT_HEADER_SIGNATURE_SIZE); + g.modified = -1; + ResetCallLog(); + TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod all"); + TEST_CALLS("VbExDiskWrite(h, 991, 32)\n" + "VbExDiskWrite(h, 1023, 1)\n"); + + /* Error reading */ + ResetMocks(); + disk_call_to_fail = 1; + TEST_NEQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail"); + WriteAndFreeGptData(handle, &g); + + /* Error writing */ + ResetMocks(); + disk_call_to_fail = 5; + AllocAndReadGptData(handle, &g); + g.modified = -1; + TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail"); +} + +/** + * Trivial invalid calls to LoadKernel() + */ +static void InvalidParamsTest(void) +{ + ResetMocks(); + lkp.bytes_per_lba = 0; + TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_PARAMETER, "Bad lba size"); + + ResetMocks(); + lkp.ending_lba = 0; + TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_PARAMETER, "Bad lba count"); + + ResetMocks(); + lkp.bytes_per_lba = 128*1024; + TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_PARAMETER, "Huge lba size"); + + ResetMocks(); + disk_call_to_fail = 1; + TEST_EQ(LoadKernel(&lkp), VBERROR_NO_KERNEL_FOUND, "Can't read disk"); + + ResetMocks(); + gpt_init_fail = 1; + TEST_EQ(LoadKernel(&lkp), VBERROR_NO_KERNEL_FOUND, "Bad GPT"); +} + +int main(void) +{ + ReadWriteGptTest(); + InvalidParamsTest(); + + return gTestSuccess ? 0 : 255; +} -- cgit v1.2.1