Already included <types.h> is supposed to provide <limits.h>. See `Documentation/contributing/coding_style.md` section `Headers and includes` Change-Id: I945eeeeccb16851f64d85cf5c67ea6e256082e11 Signed-off-by: Elyes Haouas <ehaouas@noos.fr> Reviewed-on: https://review.coreboot.org/c/coreboot/+/82724 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Jakub Czapiga <czapiga@google.com>
		
			
				
	
	
		
			201 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			201 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* SPDX-License-Identifier: GPL-2.0-only */
 | 
						|
 | 
						|
#include <drivers/efi/efivars.h>
 | 
						|
#include <vendorcode/intel/edk2/UDK2017/MdePkg/Include/Pi/PiFirmwareVolume.h>
 | 
						|
#include <vendorcode/intel/edk2/UDK2017/MdeModulePkg/Include/Guid/VariableFormat.h>
 | 
						|
#include <string.h>
 | 
						|
#include <tests/test.h>
 | 
						|
#include <types.h>
 | 
						|
 | 
						|
/* Dummy firmware volume header for a 0x30000 byte partition with a single entry
 | 
						|
 * in a formatted variable store.
 | 
						|
 */
 | 
						|
static const uint8_t FVH[] = {
 | 
						|
	/* EFI_FIRMWARE_VOLUME_HEADER */
 | 
						|
	/* UINT8 ZeroVector[16] */
 | 
						|
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
						|
	0x00, 0x00,
 | 
						|
	/* EFI_GUID FileSystemGuid */
 | 
						|
	0x8d, 0x2b, 0xf1, 0xff, 0x96, 0x76, 0x8b, 0x4c, 0xa9, 0x85, 0x27, 0x47, 0x07, 0x5b,
 | 
						|
	0x4f, 0x50,
 | 
						|
	/* UINT64 FvLength */
 | 
						|
	0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
						|
	/* UINT32 Signature */
 | 
						|
	0x5f, 0x46, 0x56, 0x48,
 | 
						|
	/* EFI_FVB_ATTRIBUTES_2 Attributes */
 | 
						|
	0x36, 0x0e, 0x00, 0x00,
 | 
						|
	/* UINT16 HeaderLength */
 | 
						|
	0x48, 0x00,
 | 
						|
	/* UINT16 Checksum */
 | 
						|
	0x00, 0xfa,
 | 
						|
	/* UINT16 ExtHeaderOffset */
 | 
						|
	0x00, 0x00,
 | 
						|
	/* UINT8 Reserved[1] */
 | 
						|
	0x00,
 | 
						|
	/* UINT8 Revision */
 | 
						|
	0x02,
 | 
						|
	/* EFI_FV_BLOCK_MAP_ENTRY BlockMap[2] */
 | 
						|
	0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
 | 
						|
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
						|
 | 
						|
	/* Variable Info Header */
 | 
						|
	/* EFI_GUID Signature */
 | 
						|
	0x78, 0x2c, 0xf3, 0xaa, 0x7b, 0x94, 0x9a, 0x43, 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3,
 | 
						|
	0x77, 0x92,
 | 
						|
	/* UINT32 Size */
 | 
						|
	0xb8, 0xff, 0x00, 0x00,
 | 
						|
	/* UINT8 Format */
 | 
						|
	0x5a,
 | 
						|
	/* UINT8 State */
 | 
						|
	0xfe,
 | 
						|
	/* UINT16 Reserved */
 | 
						|
	0x00, 0x00,
 | 
						|
	/* UINT32 Reserved1 */
 | 
						|
	0x00, 0x00, 0x00, 0x00,
 | 
						|
	/* AUTHENTICATED_VARIABLE_HEADER */
 | 
						|
	/* UINT16 StartId */
 | 
						|
	0xaa, 0x55,
 | 
						|
	/* UINT8 State */
 | 
						|
	0x3f,
 | 
						|
	/* UINT8 Reserved */
 | 
						|
	0xff,
 | 
						|
	/* UINT32 Attributes */
 | 
						|
	0x07, 0x00, 0x00, 0x00,
 | 
						|
	/* UINT64 MonotonicCount */
 | 
						|
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 | 
						|
	/* EFI_TIME TimeStamp */
 | 
						|
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 | 
						|
	0xff, 0xff, 0xff, 0xff,
 | 
						|
	/* UINT32 PubKeyIndex */
 | 
						|
	0xff, 0xff, 0xff, 0xff,
 | 
						|
	/* UINT32 NameSize */
 | 
						|
	0x12, 0x00, 0x00, 0x00,
 | 
						|
	/* UINT32 DataSize */
 | 
						|
	0x09, 0x00, 0x00, 0x00,
 | 
						|
	/* EFI_GUID VendorGuid */
 | 
						|
	0x1d, 0x4c, 0xae, 0xce, 0x5b, 0x33, 0x85, 0x46, 0xa4, 0xa0, 0xfc, 0x4a,
 | 
						|
	0x94, 0xee, 0xa0, 0x85,
 | 
						|
	/* L"coreboot" */
 | 
						|
	0x63, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x62, 0x00,
 | 
						|
	0x6f, 0x00, 0x6f, 0x00, 0x74, 0x00, 0x00, 0x00,
 | 
						|
	/* "is great" */
 | 
						|
	0x69, 0x73, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x00,
 | 
						|
};
 | 
						|
 | 
						|
#define FVH_CHECKSUMMED_SIZE (sizeof(EFI_FIRMWARE_VOLUME_HEADER) + 8 + sizeof(EFI_GUID))
 | 
						|
 | 
						|
static struct region_device flash_rdev_rw;
 | 
						|
static uint8_t flash_buffer[0x30000];
 | 
						|
 | 
						|
static const char *name = "coreboot";
 | 
						|
 | 
						|
static void mock_rdev(bool init)
 | 
						|
{
 | 
						|
	if (init) {
 | 
						|
		/* Emulate NOR flash by setting all bits to 1 */
 | 
						|
		memset(flash_buffer, 0xff, sizeof(flash_buffer));
 | 
						|
		/* Place _FVH and VIH headers, as well as test data */
 | 
						|
		memcpy(flash_buffer, FVH, sizeof(FVH));
 | 
						|
	}
 | 
						|
 | 
						|
	rdev_chain_mem_rw(&flash_rdev_rw, flash_buffer, sizeof(flash_buffer));
 | 
						|
}
 | 
						|
 | 
						|
static const EFI_GUID EficorebootNvDataGuid = {
 | 
						|
	0xceae4c1d, 0x335b, 0x4685, { 0xa4, 0xa0, 0xfc, 0x4a, 0x94, 0xee, 0xa0, 0x85 } };
 | 
						|
 | 
						|
/* Test valid and corrupted FVH header */
 | 
						|
static void efi_test_header(void **state)
 | 
						|
{
 | 
						|
	enum cb_err ret;
 | 
						|
	uint8_t buf[16];
 | 
						|
	uint32_t size;
 | 
						|
	int i;
 | 
						|
 | 
						|
	mock_rdev(true);
 | 
						|
 | 
						|
	/* Test variable lookup with intact header */
 | 
						|
	size = sizeof(buf);
 | 
						|
	ret = efi_fv_get_option(&flash_rdev_rw, &EficorebootNvDataGuid, name, buf, &size);
 | 
						|
	assert_int_equal(ret, CB_SUCCESS);
 | 
						|
	assert_int_equal(size, strlen("is great")+1);
 | 
						|
	assert_string_equal((const char *)buf, "is great");
 | 
						|
 | 
						|
	for (i = 0; i < FVH_CHECKSUMMED_SIZE; i++) {
 | 
						|
		mock_rdev(true);
 | 
						|
 | 
						|
		/* Flip some bits */
 | 
						|
		flash_buffer[i] ^= 0xff;
 | 
						|
 | 
						|
		size = sizeof(buf);
 | 
						|
		ret = efi_fv_get_option(&flash_rdev_rw, &EficorebootNvDataGuid, name, buf,
 | 
						|
					&size);
 | 
						|
		assert_int_not_equal(ret, CB_SUCCESS);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* Write with the same key and value should not modify the store */
 | 
						|
static void efi_test_noop_existing_write(void **state)
 | 
						|
{
 | 
						|
	enum cb_err ret;
 | 
						|
	int i;
 | 
						|
 | 
						|
	mock_rdev(true);
 | 
						|
 | 
						|
	ret = efi_fv_set_option(&flash_rdev_rw,
 | 
						|
				&EficorebootNvDataGuid,
 | 
						|
				name,
 | 
						|
				"is great",
 | 
						|
				strlen("is great") + 1);
 | 
						|
 | 
						|
	assert_int_equal(ret, CB_SUCCESS);
 | 
						|
 | 
						|
	for (i = sizeof(FVH); i < sizeof(flash_buffer); i++)
 | 
						|
		assert_int_equal(flash_buffer[i], 0xff);
 | 
						|
}
 | 
						|
 | 
						|
static void efi_test_new_write(void **state)
 | 
						|
{
 | 
						|
	enum cb_err ret;
 | 
						|
	uint8_t buf[16];
 | 
						|
	uint32_t size;
 | 
						|
	int i;
 | 
						|
 | 
						|
	mock_rdev(true);
 | 
						|
 | 
						|
	ret = efi_fv_set_option(&flash_rdev_rw, &EficorebootNvDataGuid,
 | 
						|
				name, "is awesome", strlen("is awesome") + 1);
 | 
						|
	assert_int_equal(ret, CB_SUCCESS);
 | 
						|
 | 
						|
	/* New variable has been written */
 | 
						|
	assert_int_equal(flash_buffer[ALIGN_UP(sizeof(FVH), 4)], 0xaa);
 | 
						|
	assert_int_equal(flash_buffer[ALIGN_UP(sizeof(FVH), 4) + 1], 0x55);
 | 
						|
 | 
						|
	/* Remaining space is blank */
 | 
						|
	for (i = ALIGN_UP(sizeof(FVH), 4) + 89; i < sizeof(flash_buffer); i++)
 | 
						|
		assert_int_equal(flash_buffer[i], 0xff);
 | 
						|
 | 
						|
	mock_rdev(false);
 | 
						|
 | 
						|
	memset(buf, 0, sizeof(buf));
 | 
						|
	size = sizeof(buf);
 | 
						|
	ret = efi_fv_get_option(&flash_rdev_rw, &EficorebootNvDataGuid, name, buf,
 | 
						|
				&size);
 | 
						|
	assert_int_equal(ret, CB_SUCCESS);
 | 
						|
	assert_int_equal(size, strlen("is awesome")+1);
 | 
						|
 | 
						|
	assert_int_equal(flash_buffer[ALIGN_UP(sizeof(FVH), 4) + 1], 0x55);
 | 
						|
	assert_string_equal((const char *)buf, "is awesome");
 | 
						|
}
 | 
						|
 | 
						|
int main(void)
 | 
						|
{
 | 
						|
	const struct CMUnitTest tests[] = {
 | 
						|
		cmocka_unit_test(efi_test_header),
 | 
						|
		cmocka_unit_test(efi_test_noop_existing_write),
 | 
						|
		cmocka_unit_test(efi_test_new_write)
 | 
						|
	};
 | 
						|
 | 
						|
	return cb_run_group_tests(tests, NULL, NULL);
 | 
						|
}
 |