Add GPT loader tests
Adds a disk image that encodes the reference partition configuration
used for block_store testing in a GPT. This is used for testing GPT
loading.
Signed-off-by: Julian Hall <julian.hall@arm.com>
Change-Id: Icb1fc6f408d9889a0dc263375addf89faa4ae20a
diff --git a/components/media/disk/test/partition_table_tests.cpp b/components/media/disk/test/partition_table_tests.cpp
new file mode 100644
index 0000000..c02e7a9
--- /dev/null
+++ b/components/media/disk/test/partition_table_tests.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#include <string>
+#include <cstring>
+#include <common/uuid/uuid.h>
+#include <service/block_storage/block_store/device/ram/ram_block_store.h>
+#include <service/block_storage/config/ref/ref_partition_configurator.h>
+#include <media/volume/index/volume_index.h>
+#include <media/volume/block_io_dev/block_io_dev.h>
+#include <media/volume/base_io_dev/base_io_dev.h>
+#include <media/disk/disk_images/ref_partition.h>
+#include <media/disk/partition_table.h>
+#include <CppUTest/TestHarness.h>
+
+TEST_GROUP(PartitionTableTests)
+{
+ void setup()
+ {
+ /* Load reference GPT image into ram block store */
+ size_t block_size = PLAT_PARTITION_BLOCK_SIZE;
+ size_t num_blocks = ref_partition_data_length / block_size;
+
+ m_block_store = ram_block_store_init(&m_ram_block_store,
+ NULL,
+ num_blocks, block_size, ref_partition_data);
+
+ CHECK_TRUE(m_block_store);
+
+ memset(m_partition_guid.octets, 0, sizeof(m_partition_guid.octets));
+
+ m_dev_handle = 0;
+ m_volume_spec = 0;
+
+ int result = block_io_dev_init(&m_block_io_dev,
+ m_block_store, &m_partition_guid,
+ &m_dev_handle, &m_volume_spec);
+
+ LONGS_EQUAL(0, result);
+ CHECK_TRUE(m_dev_handle);
+ CHECK_TRUE(m_volume_spec);
+
+ volume_index_init();
+ volume_index_add(TEST_VOLUME_ID, m_dev_handle, m_volume_spec);
+ }
+
+ void teardown()
+ {
+ block_io_dev_deinit(&m_block_io_dev);
+ ram_block_store_deinit(&m_ram_block_store);
+ volume_index_clear();
+ }
+
+ void uuid_from_canonical(uuid_t *uuid, const char *canonical)
+ {
+ uuid_parse_to_octets_reversed(canonical, (uint8_t*)uuid, sizeof(uuid_t));
+ }
+
+ void corrupt_mbr()
+ {
+ /* Scribble over the protective MBR signature */
+ static const char scribble[] = "scribble";
+ psa_status_t status = ram_block_store_modify(
+ &m_ram_block_store, 510,
+ (const uint8_t*)scribble, sizeof(scribble));
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ }
+
+ void corrupt_primary_gpt_header()
+ {
+ /* Scribble over the primary GPT header in block 1 */
+ static const char scribble[] = "scribble";
+ psa_status_t status = ram_block_store_modify(
+ &m_ram_block_store, PLAT_PARTITION_BLOCK_SIZE * 1,
+ (const uint8_t*)scribble, sizeof(scribble));
+ LONGS_EQUAL(PSA_SUCCESS, status);
+ }
+
+ static const unsigned int TEST_VOLUME_ID = 5;
+ static const uint32_t CLIENT_ID = 0;
+ static const size_t FIRST_USABLE_LBA = 34;
+
+ struct uuid_octets m_partition_guid;
+ struct block_store *m_block_store;
+ struct ram_block_store m_ram_block_store;
+ struct block_io_dev m_block_io_dev;
+ uintptr_t m_dev_handle;
+ uintptr_t m_volume_spec;
+};
+
+TEST(PartitionTableTests, loadRefPartitionTable)
+{
+ int result = load_partition_table(TEST_VOLUME_ID);
+ LONGS_EQUAL(0, result);
+
+ /* Check for expected partition entries */
+ const partition_entry_t *partition_entry = NULL;
+ uuid_t partition_guid;
+
+ uuid_from_canonical(&partition_guid, REF_PARTITION_1_GUID);
+ partition_entry = get_partition_entry_by_uuid(&partition_guid);
+ CHECK_TRUE(partition_entry);
+ UNSIGNED_LONGS_EQUAL(
+ FIRST_USABLE_LBA + REF_PARTITION_1_STARTING_LBA,
+ partition_entry->start / PLAT_PARTITION_BLOCK_SIZE);
+ UNSIGNED_LONGS_EQUAL(
+ (REF_PARTITION_1_ENDING_LBA - REF_PARTITION_1_STARTING_LBA + 1),
+ partition_entry->length / PLAT_PARTITION_BLOCK_SIZE);
+
+ uuid_from_canonical(&partition_guid, REF_PARTITION_2_GUID);
+ partition_entry = get_partition_entry_by_uuid(&partition_guid);
+ CHECK_TRUE(partition_entry);
+ UNSIGNED_LONGS_EQUAL(
+ FIRST_USABLE_LBA + REF_PARTITION_2_STARTING_LBA,
+ partition_entry->start / PLAT_PARTITION_BLOCK_SIZE);
+ UNSIGNED_LONGS_EQUAL(
+ (REF_PARTITION_2_ENDING_LBA - REF_PARTITION_2_STARTING_LBA + 1),
+ partition_entry->length / PLAT_PARTITION_BLOCK_SIZE);
+
+ uuid_from_canonical(&partition_guid, REF_PARTITION_3_GUID);
+ partition_entry = get_partition_entry_by_uuid(&partition_guid);
+ CHECK_TRUE(partition_entry);
+ UNSIGNED_LONGS_EQUAL(
+ FIRST_USABLE_LBA + REF_PARTITION_3_STARTING_LBA,
+ partition_entry->start / PLAT_PARTITION_BLOCK_SIZE);
+ UNSIGNED_LONGS_EQUAL(
+ (REF_PARTITION_3_ENDING_LBA - REF_PARTITION_3_STARTING_LBA + 1),
+ partition_entry->length / PLAT_PARTITION_BLOCK_SIZE);
+
+ uuid_from_canonical(&partition_guid, REF_PARTITION_4_GUID);
+ partition_entry = get_partition_entry_by_uuid(&partition_guid);
+ CHECK_TRUE(partition_entry);
+ UNSIGNED_LONGS_EQUAL(
+ FIRST_USABLE_LBA + REF_PARTITION_4_STARTING_LBA,
+ partition_entry->start / PLAT_PARTITION_BLOCK_SIZE);
+ UNSIGNED_LONGS_EQUAL(
+ (REF_PARTITION_4_ENDING_LBA - REF_PARTITION_4_STARTING_LBA + 1),
+ partition_entry->length / PLAT_PARTITION_BLOCK_SIZE);
+}
+
+TEST(PartitionTableTests, detectCorruptedMbr)
+{
+ corrupt_mbr();
+ int result = load_partition_table(TEST_VOLUME_ID);
+ LONGS_EQUAL(-ENOENT, result);
+}
+
+// Shows up defect in TF-A where failed GPT header CRC results in an assert.
+IGNORE_TEST(PartitionTableTests, detectCorruptedGptHeader)
+{
+ /* Load should be successful with a corrupted primary GPT header as
+ * backup is still available.
+ */
+ corrupt_primary_gpt_header();
+ int result = load_partition_table(TEST_VOLUME_ID);
+ LONGS_EQUAL(0, result);
+}