diff options
Diffstat (limited to 'tests/vb2_host_nvdata_flashrom_tests.c')
-rw-r--r-- | tests/vb2_host_nvdata_flashrom_tests.c | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/tests/vb2_host_nvdata_flashrom_tests.c b/tests/vb2_host_nvdata_flashrom_tests.c new file mode 100644 index 00000000..7a147856 --- /dev/null +++ b/tests/vb2_host_nvdata_flashrom_tests.c @@ -0,0 +1,279 @@ +/* Copyright 2020 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 crossystem flashrom-based nvdata functions. + */ + +#include <fcntl.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "2api.h" +#include "2common.h" +#include "2constants.h" +#include "2nvstorage.h" +#include "2return_codes.h" +#include "crossystem_vbnv.h" +#include "flashrom.h" +#include "test_common.h" + +/* Mocked flashrom only supports host programmer, and RW_NVRAM + region. */ +static void assert_mock_params(const char *programmer, const char *region) +{ + TEST_STR_EQ(programmer, FLASHROM_PROGRAMMER_INTERNAL_AP, + "Using internal AP programmer"); + TEST_STR_EQ(region, "RW_NVRAM", "Using NVRAM region"); +} + +static bool mock_flashrom_fail; + +/* To support both 16-byte and 64-byte nvdata with the same fake + eeprom, we can size the flash chip to be 16x64. So, for 16-byte + nvdata, this is a flash chip with 64 entries, and for 64-byte + nvdata, this is a flash chip with 16 entries. */ +static uint8_t fake_flash_region[VB2_NVDATA_SIZE * VB2_NVDATA_SIZE_V2]; +static int fake_flash_entry_count; + +static const uint8_t test_nvdata_16b[] = { + 0x60, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x4e, + 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x5e, +}; + +static const uint8_t test_nvdata2_16b[] = { + 0x60, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x4c, + 0x00, 0xfe, 0xff, 0x00, 0x00, 0xff, 0xff, 0x78, +}; + +static void reset_test_data(struct vb2_context *ctx, int nvdata_size) +{ + /* Initialize the context value. */ + ctx->flags = 0; + + switch (nvdata_size) { + case VB2_NVDATA_SIZE: + fake_flash_entry_count = VB2_NVDATA_SIZE_V2; + memcpy(ctx->nvdata, test_nvdata_16b, sizeof(test_nvdata_16b)); + break; + case VB2_NVDATA_SIZE_V2: + ctx->flags |= VB2_CONTEXT_NVDATA_V2; + fake_flash_entry_count = VB2_NVDATA_SIZE; + /* TODO: create some test data for 64-byte nvdata and + put it here. Right now, this only tests 16-byte + nvdata. */ + break; + default: + /* This is not valid. */ + TEST_TRUE(false, "Test failed, invalid nvdata size"); + fake_flash_entry_count = 0; + break; + } + + /* Clear the fake flash chip. */ + memset(fake_flash_region, 0xff, sizeof(fake_flash_region)); + + /* Flashrom succeeds unless the test says otherwise. */ + mock_flashrom_fail = false; +} + +/* Mocked flashrom_read for tests. */ +vb2_error_t flashrom_read(const char *programmer, const char *region, + uint8_t **data_out, uint32_t *size_out) +{ + if (mock_flashrom_fail) { + *data_out = NULL; + *size_out = 0; + return VB2_ERROR_FLASHROM; + } + + assert_mock_params(programmer, region); + + *data_out = malloc(sizeof(fake_flash_region)); + *size_out = sizeof(fake_flash_region); + memcpy(*data_out, fake_flash_region, sizeof(fake_flash_region)); + return VB2_SUCCESS; +} + +/* Mocked flashrom_write for tests. */ +vb2_error_t flashrom_write(const char *programmer, const char *region, + uint8_t *data, uint32_t data_size) +{ + if (mock_flashrom_fail) + return VB2_ERROR_FLASHROM; + + assert_mock_params(programmer, region); + + TEST_EQ(data_size, sizeof(fake_flash_region), + "The flash size is correct"); + memcpy(fake_flash_region, data, data_size); + return VB2_SUCCESS; +} + +static void test_read_ok_beginning(void) +{ + struct vb2_context ctx; + + reset_test_data(&ctx, sizeof(test_nvdata_16b)); + memcpy(fake_flash_region, test_nvdata2_16b, sizeof(test_nvdata2_16b)); + + TEST_EQ(vb2_read_nv_storage_flashrom(&ctx), 0, + "Reading storage succeeds"); + TEST_EQ(memcmp(ctx.nvdata, test_nvdata2_16b, sizeof(test_nvdata2_16b)), + 0, "The nvdata in the vb2_context was updated from flash"); +} + +static void test_read_ok_2ndentry(void) +{ + struct vb2_context ctx; + + reset_test_data(&ctx, sizeof(test_nvdata_16b)); + memcpy(fake_flash_region, test_nvdata_16b, sizeof(test_nvdata_16b)); + memcpy(fake_flash_region + VB2_NVDATA_SIZE, test_nvdata2_16b, + sizeof(test_nvdata2_16b)); + + TEST_EQ(vb2_read_nv_storage_flashrom(&ctx), 0, + "Reading storage succeeds"); + TEST_EQ(memcmp(ctx.nvdata, test_nvdata2_16b, sizeof(test_nvdata2_16b)), + 0, "The nvdata in the vb2_context was updated from flash"); +} + +static void test_read_ok_full(void) +{ + struct vb2_context ctx; + + reset_test_data(&ctx, sizeof(test_nvdata_16b)); + + for (int entry = 0; entry < fake_flash_entry_count - 2; entry++) + memcpy(fake_flash_region + (entry * VB2_NVDATA_SIZE), + test_nvdata_16b, sizeof(test_nvdata_16b)); + + memcpy(fake_flash_region + + ((fake_flash_entry_count - 2) * VB2_NVDATA_SIZE), + test_nvdata2_16b, sizeof(test_nvdata2_16b)); + + TEST_EQ(vb2_read_nv_storage_flashrom(&ctx), 0, + "Reading storage succeeds"); + TEST_EQ(memcmp(ctx.nvdata, test_nvdata2_16b, sizeof(test_nvdata2_16b)), + 0, "The nvdata in the vb2_context was updated from flash"); +} + +static void test_read_fail_uninitialized(void) +{ + struct vb2_context ctx; + + reset_test_data(&ctx, sizeof(test_nvdata_16b)); + + TEST_NEQ(vb2_read_nv_storage_flashrom(&ctx), 0, + "Reading storage fails when flash is erased"); +} + +static void test_read_fail_flashrom(void) +{ + struct vb2_context ctx; + + reset_test_data(&ctx, sizeof(test_nvdata_16b)); + memcpy(fake_flash_region, test_nvdata_16b, sizeof(test_nvdata_16b)); + mock_flashrom_fail = true; + + TEST_NEQ(vb2_read_nv_storage_flashrom(&ctx), 0, + "Reading storage fails when flashrom fails"); +} + +static void test_write_ok_beginning(void) +{ + struct vb2_context ctx; + + reset_test_data(&ctx, sizeof(test_nvdata_16b)); + memcpy(fake_flash_region, test_nvdata_16b, sizeof(test_nvdata_16b)); + memcpy(ctx.nvdata, test_nvdata2_16b, sizeof(test_nvdata2_16b)); + + TEST_EQ(vb2_write_nv_storage_flashrom(&ctx), 0, + "Writing storage succeeds"); + TEST_EQ(memcmp(fake_flash_region + VB2_NVDATA_SIZE, test_nvdata2_16b, + sizeof(test_nvdata2_16b)), + 0, "The flash was updated with a new entry"); +} + +static void test_write_ok_2ndentry(void) +{ + struct vb2_context ctx; + + reset_test_data(&ctx, sizeof(test_nvdata_16b)); + memcpy(fake_flash_region, test_nvdata_16b, sizeof(test_nvdata_16b)); + memcpy(fake_flash_region + VB2_NVDATA_SIZE, test_nvdata_16b, + sizeof(test_nvdata_16b)); + memcpy(ctx.nvdata, test_nvdata2_16b, sizeof(test_nvdata2_16b)); + + TEST_EQ(vb2_write_nv_storage_flashrom(&ctx), 0, + "Writing storage succeeds"); + TEST_EQ(memcmp(fake_flash_region + (2 * VB2_NVDATA_SIZE), + test_nvdata2_16b, sizeof(test_nvdata2_16b)), + 0, "The flash was updated with a new entry"); +} + +static void test_write_ok_full(void) +{ + struct vb2_context ctx; + uint8_t expected_flash[sizeof(fake_flash_region)]; + + reset_test_data(&ctx, sizeof(test_nvdata_16b)); + + for (int entry = 0; entry < fake_flash_entry_count - 1; entry++) + memcpy(fake_flash_region + (entry * VB2_NVDATA_SIZE), + test_nvdata_16b, sizeof(test_nvdata_16b)); + + memcpy(expected_flash, test_nvdata2_16b, sizeof(test_nvdata2_16b)); + memset(expected_flash + VB2_NVDATA_SIZE, 0xff, + sizeof(expected_flash) - VB2_NVDATA_SIZE); + memcpy(ctx.nvdata, test_nvdata2_16b, sizeof(test_nvdata2_16b)); + + TEST_EQ(vb2_write_nv_storage_flashrom(&ctx), 0, + "Writing storage succeeds"); + TEST_EQ(memcmp(fake_flash_region, expected_flash, + sizeof(expected_flash)), + 0, + "The flash was erased and the new entry was placed at " + "the beginning"); +} + +static void test_write_fail_uninitialized(void) +{ + struct vb2_context ctx; + + reset_test_data(&ctx, sizeof(test_nvdata_16b)); + + TEST_NEQ(vb2_write_nv_storage_flashrom(&ctx), 0, + "Writing storage fails when the flash is erased"); +} + +static void test_write_fail_flashrom(void) +{ + struct vb2_context ctx; + + reset_test_data(&ctx, sizeof(test_nvdata_16b)); + memcpy(fake_flash_region, test_nvdata_16b, sizeof(test_nvdata_16b)); + mock_flashrom_fail = true; + + TEST_NEQ(vb2_write_nv_storage_flashrom(&ctx), 0, + "Writing storage fails when flashrom fails"); +} + +int main(int argc, char *argv[]) +{ + test_read_ok_beginning(); + test_read_ok_2ndentry(); + test_read_ok_full(); + test_read_fail_uninitialized(); + test_read_fail_flashrom(); + test_write_ok_beginning(); + test_write_ok_2ndentry(); + test_write_ok_full(); + test_write_fail_uninitialized(); + test_write_fail_flashrom(); + + return gTestSuccess ? 0 : 255; +} |