diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/chip.c | 226 | ||||
| -rw-r--r-- | tests/meson.build | 1 | ||||
| -rw-r--r-- | tests/tests.c | 6 | ||||
| -rw-r--r-- | tests/tests.h | 4 | 
4 files changed, 237 insertions, 0 deletions
| diff --git a/tests/chip.c b/tests/chip.c new file mode 100644 index 00000000..0cb05ad8 --- /dev/null +++ b/tests/chip.c @@ -0,0 +1,226 @@ +/* + * This file is part of the flashrom project. + * + * Copyright 2021 Google LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <include/test.h> +#include <stdio.h> +#include <string.h> + +#include "chipdrivers.h" +#include "flash.h" +#include "programmer.h" + +#define CHIP_TOTAL_SIZE 8192 + +static struct { +	unsigned int unlock_calls; /* how many times unlock function was called */ +	uint8_t buf[CHIP_TOTAL_SIZE]; /* buffer of total size of chip, to emulate a chip */ +} g_chip_state = { +	.unlock_calls = 0, +	.buf = { 0 }, +}; + +int read_chip(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len) +{ +	printf("Read chip called with start=0x%x, len=0x%x\n", start, len); +	if (!g_chip_state.unlock_calls) { +		printf("Error while reading chip: unlock was not called.\n"); +		return 1; +	} + +	assert_in_range(start + len, 0, CHIP_TOTAL_SIZE); + +	memcpy(buf, &g_chip_state.buf[start], len); +	return 0; +} + +int write_chip(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len) +{ +	printf("Write chip called with start=0x%x, len=0x%x\n", start, len); +	if (!g_chip_state.unlock_calls) { +		printf("Error while writing chip: unlock was not called.\n"); +		return 1; +	} + +	assert_in_range(start + len, 0, CHIP_TOTAL_SIZE); + +	memcpy(&g_chip_state.buf[start], buf, len); +	return 0; +} + +int unlock_chip(struct flashctx *flash) +{ +	printf("Unlock chip called\n"); +	g_chip_state.unlock_calls++; + +	if (g_chip_state.unlock_calls > 1) { +		printf("Error: Unlock called twice\n"); +		return -1; +	} + +	return 0; +} + +int block_erase_chip(struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen) +{ +	printf("Block erase called with blockaddr=0x%x, blocklen=0x%x\n", blockaddr, blocklen); +	if (!g_chip_state.unlock_calls) { +		printf("Error while erasing chip: unlock was not called.\n"); +		return 1; +	} + +	assert_in_range(blockaddr + blocklen, 0, CHIP_TOTAL_SIZE); + +	memset(&g_chip_state.buf[blockaddr], 0xff, blocklen); +	return 0; +} + +void erase_chip_test_success(void **state) +{ +	(void) state; /* unused */ + +	struct flashchip chip = { +		.vendor		= "aklm", +		/* +		 * Total size less than 16 to skip some steps +		 * in flashrom.c#prepare_flash_access. +		 */ +		.total_size	= 8, +		.tested		= TEST_OK_PREW, +		.read		= read_chip, +		.write		= write_chip, +		.unlock		= unlock_chip, +		.block_erasers	= +		{{ +			 /* All blocks within total size of the chip. */ +			.eraseblocks = { {2 * 1024, 4} }, +			.block_erase = block_erase_chip, +		 }}, +	}; +	struct flashrom_flashctx flash = { +		.chip = &chip, +	}; + +	struct flashrom_layout *layout; + +	printf("Creating layout with one included region... "); +	assert_int_equal(0, flashrom_layout_new(&layout)); +	/* One region which covers total size of chip. */ +	assert_int_equal(0, flashrom_layout_add_region(layout, 0, chip.total_size * 1024 - 1, "region")); +	assert_int_equal(0, flashrom_layout_include_region(layout, "region")); + +	flashrom_layout_set(&flash, layout); +	printf("done\n"); + +	/* +	 * We need some programmer (any), and dummy is a very good one, +	 * because it doesn't need any mocking. So no extra complexity +	 * from a programmer side, and test can focus on the code which +	 * erases the chip. +	 */ +	const char *param = ""; /* default values for all params */ +	printf("Dummyflasher initialising... "); +	assert_int_equal(0, programmer_init(&programmer_dummy, param)); +	printf("done\n"); + +	printf("Erase chip operation started.\n"); +	assert_int_equal(0, do_erase(&flash)); +	printf("Erase chip operation done.\n"); + +	printf("Dummyflasher shutdown... "); +	assert_int_equal(0, programmer_shutdown()); +	printf("done\n"); + +	printf("Releasing layout... "); +	flashrom_layout_release(layout); +	printf("done\n"); +} + +void erase_chip_with_dummyflasher_test_success(void **state) +{ +	(void) state; /* unused */ + +	struct flashchip chip = { +		.vendor		= "aklm&dummyflasher", +		/* +		 * Setup the values for W25Q128.V because we ask dummyflasher +		 * to emulate this chip. All operations: read/write/unlock/erase +		 * are real, not mocks, and they are expected to be handled by +		 * dummyflasher. +		 */ +		.total_size	= 16 * 1024, +		.tested		= TEST_OK_PREW, +		.read		= spi_chip_read, +		.write		= spi_chip_write_256, +		.unlock         = spi_disable_blockprotect, +		.block_erasers  = +		{ +			{ +				.eraseblocks = { {4 * 1024, 4096} }, +				.block_erase = spi_block_erase_20, +			}, { +				.eraseblocks = { {32 * 1024, 512} }, +				.block_erase = spi_block_erase_52, +			}, { +				.eraseblocks = { {64 * 1024, 256} }, +				.block_erase = spi_block_erase_d8, +			}, { +				.eraseblocks = { {16 * 1024 * 1024, 1} }, +				.block_erase = spi_block_erase_60, +			}, { +				.eraseblocks = { {16 * 1024 * 1024, 1} }, +				.block_erase = spi_block_erase_c7, +			} +		}, +	}; +	struct flashrom_flashctx flash = { +		.chip = &chip, +	}; + +	struct flashrom_layout *layout; + +	printf("Creating layout with one included region... "); +	assert_int_equal(0, flashrom_layout_new(&layout)); +	/* One region which covers total size of chip. */ +	assert_int_equal(0, flashrom_layout_add_region(layout, 0, chip.total_size * 1024 - 1, "region")); +	assert_int_equal(0, flashrom_layout_include_region(layout, "region")); + +	flashrom_layout_set(&flash, layout); +	printf("done\n"); + +	/* +	 * Dummyflasher is capable to emulate a chip, so we ask it to do this. +	 * Nothing to mock, dummy is taking care of this already. +	 */ +	char *param_dup = strdup("bus=spi,emulate=W25Q128FV"); +	printf("Dummyflasher initialising to emulate W25Q128FV... "); +	assert_int_equal(0, programmer_init(&programmer_dummy, param_dup)); +	/* Assignment below normally happens while probing, but this test is not probing. */ +	flash.mst = ®istered_masters[0]; +	printf("done\n"); + +	printf("Erase chip operation started.\n"); +	assert_int_equal(0, do_erase(&flash)); +	printf("Erase chip operation done.\n"); + +	printf("Dummyflasher shutdown... "); +	assert_int_equal(0, programmer_shutdown()); +	printf("done\n"); + +	printf("Releasing layout... "); +	flashrom_layout_release(layout); +	printf("done\n"); + +	free(param_dup); +} diff --git a/tests/meson.build b/tests/meson.build index 2bde3f01..63fec5aa 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -20,6 +20,7 @@ srcs = [    'spi25.c',    'init_shutdown.c',    'layout.c', +  'chip.c',  ]  mocks = [ diff --git a/tests/tests.c b/tests/tests.c index 13686326..bfc0e53c 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -292,5 +292,11 @@ int main(void)  	};  	ret |= cmocka_run_group_tests_name("layout.c tests", layout_tests, NULL, NULL); +	const struct CMUnitTest chip_tests[] = { +		cmocka_unit_test(erase_chip_test_success), +		cmocka_unit_test(erase_chip_with_dummyflasher_test_success), +	}; +	ret |= cmocka_run_group_tests_name("chip.c tests", chip_tests, NULL, NULL); +  	return ret;  } diff --git a/tests/tests.h b/tests/tests.h index 2b03458c..512b72d0 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -57,4 +57,8 @@ void layout_pass_sanity_checks_test_success(void **state);  void layout_region_invalid_address_test_success(void **state);  void layout_region_invalid_range_test_success(void **state); +/* chip.c */ +void erase_chip_test_success(void **state); +void erase_chip_with_dummyflasher_test_success(void **state); +  #endif /* TESTS_H */ | 
