summaryrefslogtreecommitdiffstats
path: root/vpnor/test
diff options
context:
space:
mode:
Diffstat (limited to 'vpnor/test')
-rw-r--r--vpnor/test/Makefile.am.include267
-rw-r--r--vpnor/test/create_pnor_partition_table.cpp81
-rw-r--r--vpnor/test/create_read_window_oob.cpp65
-rw-r--r--vpnor/test/create_read_window_partition_exists.cpp78
-rw-r--r--vpnor/test/create_read_window_partition_invalid.cpp56
-rw-r--r--vpnor/test/create_read_window_remap.cpp77
-rw-r--r--vpnor/test/create_read_window_size.cpp77
-rw-r--r--vpnor/test/create_read_window_straddle_partitions.cpp74
-rw-r--r--vpnor/test/create_read_window_toc.cpp81
-rw-r--r--vpnor/test/create_write_window_ro_partition.cpp64
-rw-r--r--vpnor/test/create_write_window_rw_partition.cpp64
-rw-r--r--vpnor/test/create_write_window_unmapped.cpp65
-rw-r--r--vpnor/test/dump_flash.cpp92
-rw-r--r--vpnor/test/read_patch.cpp72
-rw-r--r--vpnor/test/tmpd.cpp42
-rw-r--r--vpnor/test/tmpd.hpp102
-rw-r--r--vpnor/test/toc_flags.cpp77
-rw-r--r--vpnor/test/toc_lookup_failed.cpp54
-rw-r--r--vpnor/test/toc_lookup_found.cpp50
-rw-r--r--vpnor/test/toc_missing_file.cpp55
-rw-r--r--vpnor/test/toc_no_end.cpp29
-rw-r--r--vpnor/test/toc_no_name.cpp28
-rw-r--r--vpnor/test/toc_no_start.cpp29
-rw-r--r--vpnor/test/toc_no_version.cpp29
-rw-r--r--vpnor/test/toc_overlap.cpp52
-rw-r--r--vpnor/test/toc_start_gt_end.cpp28
-rw-r--r--vpnor/test/write_patch.cpp82
-rw-r--r--vpnor/test/write_patch_resize.cpp74
-rw-r--r--vpnor/test/write_prsv.cpp64
-rw-r--r--vpnor/test/write_ro.cpp50
-rw-r--r--vpnor/test/write_rw.cpp97
31 files changed, 2155 insertions, 0 deletions
diff --git a/vpnor/test/Makefile.am.include b/vpnor/test/Makefile.am.include
new file mode 100644
index 0000000..9a81d9c
--- /dev/null
+++ b/vpnor/test/Makefile.am.include
@@ -0,0 +1,267 @@
+TEST_MBOX_VPNOR_SRCS = \
+ common.c \
+ vpnor/pnor_partition_table.cpp \
+ %reldir%/tmpd.cpp
+
+TEST_MBOX_VPNOR_INTEG_SRCS = \
+ common.c \
+ mboxd_msg.c \
+ mboxd_windows.c \
+ mboxd_lpc.c \
+ vpnor/mboxd_lpc_reset.cpp \
+ vpnor/mboxd_pnor_partition_table.cpp \
+ vpnor/mboxd_flash.cpp \
+ vpnor/pnor_partition.cpp \
+ vpnor/pnor_partition_table.cpp \
+ %reldir%/tmpd.cpp
+
+VPNOR_LDADD = -lstdc++fs \
+ $(SDBUSPLUS_LIBS) \
+ $(PHOSPHOR_LOGGING_LIBS) \
+ $(PHOSPHOR_DBUS_INTERFACES_LIBS)
+
+vpnor_test_create_pnor_partition_table_SOURCES = \
+ $(TEST_MOCK_SRCS) \
+ $(TEST_MBOX_VPNOR_INTEG_SRCS) \
+ %reldir%/create_pnor_partition_table.cpp
+vpnor_test_create_pnor_partition_table_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_create_pnor_partition_table_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_create_read_window_partition_exists_SOURCES = \
+ $(TEST_MOCK_SRCS) \
+ $(TEST_MBOX_VPNOR_INTEG_SRCS) \
+ %reldir%/create_read_window_partition_exists.cpp
+vpnor_test_create_read_window_partition_exists_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_create_read_window_partition_exists_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_write_patch_SOURCES = \
+ $(TEST_MBOX_VPNOR_SRCS) \
+ mtd.c \
+ vpnor/mboxd_pnor_partition_table.cpp \
+ vpnor/mboxd_flash.cpp \
+ vpnor/pnor_partition.cpp \
+ %reldir%/write_patch.cpp
+vpnor_test_write_patch_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_write_patch_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_write_prsv_SOURCES = \
+ $(TEST_MBOX_VPNOR_SRCS) \
+ mtd.c \
+ vpnor/mboxd_pnor_partition_table.cpp \
+ vpnor/mboxd_flash.cpp \
+ vpnor/pnor_partition.cpp \
+ %reldir%/write_prsv.cpp
+vpnor_test_write_prsv_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_write_prsv_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_write_ro_SOURCES = \
+ $(TEST_MBOX_VPNOR_SRCS) \
+ mtd.c \
+ vpnor/mboxd_pnor_partition_table.cpp \
+ vpnor/mboxd_flash.cpp \
+ vpnor/pnor_partition.cpp \
+ %reldir%/write_ro.cpp
+vpnor_test_write_ro_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_write_ro_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_write_rw_SOURCES = \
+ $(TEST_MBOX_VPNOR_SRCS) \
+ mtd.c \
+ vpnor/mboxd_pnor_partition_table.cpp \
+ vpnor/mboxd_flash.cpp \
+ vpnor/pnor_partition.cpp \
+ %reldir%/write_rw.cpp
+vpnor_test_write_rw_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_write_rw_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_toc_no_name_SOURCES = \
+ common.c \
+ vpnor/pnor_partition_table.cpp \
+ %reldir%/toc_no_name.cpp
+vpnor_test_toc_no_name_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_toc_no_name_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_toc_start_gt_end_SOURCES = \
+ common.c \
+ vpnor/pnor_partition_table.cpp \
+ %reldir%/toc_start_gt_end.cpp
+vpnor_test_toc_start_gt_end_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_toc_start_gt_end_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_toc_no_start_SOURCES = \
+ common.c \
+ vpnor/pnor_partition_table.cpp \
+ %reldir%/toc_no_start.cpp
+vpnor_test_toc_no_start_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_toc_no_start_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_toc_no_end_SOURCES = \
+ common.c \
+ vpnor/pnor_partition_table.cpp \
+ %reldir%/toc_no_end.cpp
+vpnor_test_toc_no_end_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_toc_no_end_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_toc_no_version_SOURCES = \
+ common.c \
+ vpnor/pnor_partition_table.cpp \
+ %reldir%/toc_no_version.cpp
+vpnor_test_toc_no_version_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_toc_no_version_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_toc_flags_SOURCES = \
+ common.c \
+ vpnor/pnor_partition_table.cpp \
+ %reldir%/toc_flags.cpp
+vpnor_test_toc_flags_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_toc_flags_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_toc_overlap_SOURCES = \
+ $(TEST_MOCK_SRCS) \
+ $(TEST_MBOX_VPNOR_INTEG_SRCS) \
+ %reldir%/toc_overlap.cpp
+vpnor_test_toc_overlap_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_toc_overlap_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_toc_lookup_found_SOURCES = \
+ $(TEST_MOCK_SRCS) \
+ $(TEST_MBOX_VPNOR_INTEG_SRCS) \
+ %reldir%/toc_lookup_found.cpp
+vpnor_test_toc_lookup_found_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_toc_lookup_found_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_toc_lookup_failed_SOURCES = \
+ $(TEST_MOCK_SRCS) \
+ $(TEST_MBOX_VPNOR_INTEG_SRCS) \
+ %reldir%/toc_lookup_failed.cpp
+vpnor_test_toc_lookup_failed_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_toc_lookup_failed_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_toc_missing_file_SOURCES = \
+ $(TEST_MOCK_SRCS) \
+ $(TEST_MBOX_VPNOR_INTEG_SRCS) \
+ %reldir%/toc_missing_file.cpp
+vpnor_test_toc_missing_file_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_toc_missing_file_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_create_read_window_oob_SOURCES = \
+ $(TEST_MOCK_SRCS) \
+ $(TEST_MBOX_VPNOR_INTEG_SRCS) \
+ %reldir%/create_read_window_oob.cpp
+vpnor_test_create_read_window_oob_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_create_read_window_oob_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_create_read_window_toc_SOURCES = \
+ $(TEST_MOCK_SRCS) \
+ $(TEST_MBOX_VPNOR_INTEG_SRCS) \
+ %reldir%/create_read_window_toc.cpp
+vpnor_test_create_read_window_toc_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_create_read_window_toc_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_create_read_window_straddle_partitions_SOURCES = \
+ $(TEST_MOCK_SRCS) \
+ $(TEST_MBOX_VPNOR_INTEG_SRCS) \
+ %reldir%/create_read_window_straddle_partitions.cpp
+vpnor_test_create_read_window_straddle_partitions_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_create_read_window_straddle_partitions_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_create_read_window_partition_invalid_SOURCES = \
+ $(TEST_MOCK_SRCS) \
+ $(TEST_MBOX_VPNOR_INTEG_SRCS) \
+ %reldir%/create_read_window_partition_invalid.cpp
+vpnor_test_create_read_window_partition_invalid_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_create_read_window_partition_invalid_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_read_patch_SOURCES = \
+ $(TEST_MOCK_SRCS) \
+ $(TEST_MBOX_VPNOR_INTEG_SRCS) \
+ %reldir%/read_patch.cpp
+vpnor_test_read_patch_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_read_patch_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_write_patch_resize_SOURCES = \
+ $(TEST_MBOX_VPNOR_SRCS) \
+ mtd.c \
+ vpnor/mboxd_pnor_partition_table.cpp \
+ vpnor/mboxd_flash.cpp \
+ vpnor/pnor_partition.cpp \
+ %reldir%/write_patch_resize.cpp
+vpnor_test_write_patch_resize_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_write_patch_resize_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_dump_flash_SOURCES = \
+ $(TEST_MOCK_SRCS) \
+ $(TEST_MBOX_VPNOR_INTEG_SRCS) \
+ %reldir%/dump_flash.cpp
+vpnor_test_dump_flash_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_dump_flash_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_create_read_window_size_SOURCES = \
+ $(TEST_MOCK_SRCS) \
+ $(TEST_MBOX_VPNOR_INTEG_SRCS) \
+ %reldir%/create_read_window_size.cpp
+vpnor_test_create_read_window_size_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_create_read_window_size_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_create_read_window_remap_SOURCES = \
+ $(TEST_MOCK_SRCS) \
+ $(TEST_MBOX_VPNOR_INTEG_SRCS) \
+ %reldir%/create_read_window_remap.cpp
+vpnor_test_create_read_window_remap_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_create_read_window_remap_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_create_write_window_ro_partition_SOURCES = \
+ $(TEST_MOCK_SRCS) \
+ $(TEST_MBOX_VPNOR_INTEG_SRCS) \
+ %reldir%/create_write_window_ro_partition.cpp
+vpnor_test_create_write_window_ro_partition_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_create_write_window_ro_partition_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_create_write_window_rw_partition_SOURCES = \
+ $(TEST_MOCK_SRCS) \
+ $(TEST_MBOX_VPNOR_INTEG_SRCS) \
+ %reldir%/create_write_window_rw_partition.cpp
+vpnor_test_create_write_window_rw_partition_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_create_write_window_rw_partition_LDADD = $(VPNOR_LDADD)
+
+vpnor_test_create_write_window_unmapped_SOURCES = \
+ $(TEST_MOCK_SRCS) \
+ $(TEST_MBOX_VPNOR_INTEG_SRCS) \
+ %reldir%/create_write_window_unmapped.cpp
+vpnor_test_create_write_window_unmapped_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_create_write_window_unmapped_LDADD = $(VPNOR_LDADD)
+
+if VIRTUAL_PNOR_ENABLED
+check_PROGRAMS += \
+ %reldir%/create_pnor_partition_table \
+ %reldir%/create_read_window_partition_exists \
+ %reldir%/write_prsv \
+ %reldir%/write_ro \
+ %reldir%/write_rw \
+ %reldir%/write_patch \
+ %reldir%/toc_no_name \
+ %reldir%/toc_start_gt_end \
+ %reldir%/toc_no_start \
+ %reldir%/toc_no_end \
+ %reldir%/toc_no_version \
+ %reldir%/toc_flags \
+ %reldir%/toc_overlap \
+ %reldir%/toc_lookup_found \
+ %reldir%/toc_lookup_failed \
+ %reldir%/toc_missing_file \
+ %reldir%/create_read_window_oob \
+ %reldir%/create_read_window_toc \
+ %reldir%/create_read_window_straddle_partitions \
+ %reldir%/create_read_window_partition_invalid \
+ %reldir%/read_patch \
+ %reldir%/write_patch_resize \
+ %reldir%/dump_flash \
+ %reldir%/create_read_window_size \
+ %reldir%/create_read_window_remap \
+ %reldir%/create_write_window_ro_partition \
+ %reldir%/create_write_window_rw_partition \
+ %reldir%/create_write_window_unmapped
+
+XFAIL_TESTS += %reldir%/create_write_window_ro_partition
+XFAIL_TESTS += %reldir%/create_write_window_unmapped
+endif
diff --git a/vpnor/test/create_pnor_partition_table.cpp b/vpnor/test/create_pnor_partition_table.cpp
new file mode 100644
index 0000000..3a46e38
--- /dev/null
+++ b/vpnor/test/create_pnor_partition_table.cpp
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+#include <assert.h>
+#include <string.h>
+
+#include "config.h"
+#include "vpnor/pnor_partition_table.hpp"
+
+extern "C" {
+#include "test/mbox.h"
+#include "test/system.h"
+}
+
+#include "vpnor/test/tmpd.hpp"
+
+static const auto BLOCK_SIZE = 4 * 1024;
+static const auto ERASE_SIZE = BLOCK_SIZE;
+static const auto PNOR_SIZE = 64 * 1024 * 1024;
+static const auto MEM_SIZE = PNOR_SIZE;
+static const auto N_WINDOWS = 1;
+static const auto WINDOW_SIZE = BLOCK_SIZE;
+
+const std::string toc[] = {
+ "partition01=HBB,00000000,00001000,80,ECC,PRESERVED",
+};
+constexpr auto partitionName = "HBB";
+
+namespace test = openpower::virtual_pnor::test;
+
+int main()
+{
+ struct mbox_context* ctx;
+
+ system_set_reserved_size(MEM_SIZE);
+ system_set_mtd_sizes(PNOR_SIZE, ERASE_SIZE);
+ ctx = mbox_create_test_context(N_WINDOWS, WINDOW_SIZE);
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+ const openpower::virtual_pnor::partition::Table table(ctx);
+
+ pnor_partition_table expectedTable{};
+ expectedTable.data.magic = PARTITION_HEADER_MAGIC;
+ expectedTable.data.version = PARTITION_VERSION_1;
+ expectedTable.data.size = 1;
+ expectedTable.data.entry_size = sizeof(pnor_partition);
+ expectedTable.data.entry_count = 1;
+ expectedTable.data.block_size = BLOCK_SIZE;
+ expectedTable.data.block_count =
+ (PNOR_SIZE) / expectedTable.data.block_size;
+ expectedTable.checksum =
+ openpower::virtual_pnor::details::checksum(expectedTable.data);
+
+ pnor_partition expectedPartition{};
+ strcpy(expectedPartition.data.name, partitionName);
+ expectedPartition.data.base = 0;
+ expectedPartition.data.size = 1;
+ expectedPartition.data.actual = 0x1000;
+ expectedPartition.data.id = 1;
+ expectedPartition.data.pid = PARENT_PATITION_ID;
+ expectedPartition.data.type = PARTITION_TYPE_DATA;
+ expectedPartition.data.flags = 0;
+ expectedPartition.data.user.data[0] = PARTITION_ECC_PROTECTED;
+ expectedPartition.data.user.data[1] |= PARTITION_PRESERVED;
+ expectedPartition.data.user.data[1] |= PARTITION_VERSION_CHECK_SHA512;
+ expectedPartition.checksum =
+ openpower::virtual_pnor::details::checksum(expectedPartition.data);
+
+ const pnor_partition_table& result = table.getNativeTable();
+
+ auto rc = memcmp(&expectedTable, &result, sizeof(pnor_partition_table));
+ assert(rc == 0);
+
+ rc = memcmp(&expectedPartition, &result.partitions[0],
+ sizeof(pnor_partition));
+ assert(rc == 0);
+
+ const pnor_partition& first = table.partition(0);
+ rc = memcmp(&first, &result.partitions[0], sizeof(pnor_partition));
+ assert(rc == 0);
+
+ return 0;
+}
diff --git a/vpnor/test/create_read_window_oob.cpp b/vpnor/test/create_read_window_oob.cpp
new file mode 100644
index 0000000..445b0a1
--- /dev/null
+++ b/vpnor/test/create_read_window_oob.cpp
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include <assert.h>
+#include <string.h>
+
+#include "config.h"
+#include "vpnor/mboxd_pnor_partition_table.h"
+
+extern "C" {
+#include "test/mbox.h"
+#include "test/system.h"
+}
+
+#include "vpnor/test/tmpd.hpp"
+
+const std::string toc[] = {
+ "partition01=HBB,00001000,00002000,80,ECC,READONLY",
+};
+
+static constexpr auto BLOCK_SIZE = 4096;
+static constexpr auto MEM_SIZE = (BLOCK_SIZE * 2);
+static constexpr auto ERASE_SIZE = BLOCK_SIZE;
+static constexpr auto N_WINDOWS = 1;
+static constexpr auto WINDOW_SIZE = BLOCK_SIZE;
+static constexpr auto PNOR_SIZE = (BLOCK_SIZE * 4);
+
+static const uint8_t get_info[] = {0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+/* Request access beyond the last (only) partition */
+static const uint8_t create_read_window[] = {0x04, 0x01, 0x03, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+static const uint8_t response[] = {0x04, 0x01, 0xfe, 0xff, 0x01, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
+
+int main()
+{
+ namespace test = openpower::virtual_pnor::test;
+
+ struct mbox_context *ctx;
+ int rc;
+
+ system_set_reserved_size(MEM_SIZE);
+ system_set_mtd_sizes(PNOR_SIZE, ERASE_SIZE);
+
+ ctx = mbox_create_test_context(N_WINDOWS, WINDOW_SIZE);
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+ init_vpnor_from_paths(ctx);
+
+ rc = mbox_command_dispatch(ctx, get_info, sizeof(get_info));
+ assert(rc == 1);
+
+ rc = mbox_command_dispatch(ctx, create_read_window,
+ sizeof(create_read_window));
+ assert(rc == 1);
+
+ rc = mbox_cmp(ctx, response, sizeof(response));
+ assert(rc == 0);
+
+ return 0;
+}
diff --git a/vpnor/test/create_read_window_partition_exists.cpp b/vpnor/test/create_read_window_partition_exists.cpp
new file mode 100644
index 0000000..12ac19b
--- /dev/null
+++ b/vpnor/test/create_read_window_partition_exists.cpp
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include <assert.h>
+#include <experimental/filesystem>
+#include <fstream>
+#include <string.h>
+#include <vector>
+
+#include "config.h"
+#include "vpnor/mboxd_pnor_partition_table.h"
+
+extern "C" {
+#include "test/mbox.h"
+#include "test/system.h"
+}
+
+#include "vpnor/test/tmpd.hpp"
+
+// A read window assumes that the toc is located at offset 0,
+// so create dummy partition at arbitrary offset 0x1000.
+const std::string toc[] = {
+ "partition01=HBB,00001000,00002000,80,ECC,READONLY",
+};
+
+static const uint8_t data[8] = {0xaa, 0x55, 0xaa, 0x66, 0x77, 0x88, 0x99, 0xab};
+
+static const auto BLOCK_SIZE = 4096;
+static const auto MEM_SIZE = BLOCK_SIZE * 2;
+static const auto ERASE_SIZE = BLOCK_SIZE;
+static const auto N_WINDOWS = 1;
+static const auto WINDOW_SIZE = BLOCK_SIZE;
+
+static const uint8_t get_info[] = {0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+// offset 0x100 and size 6
+static const uint8_t create_read_window[] = {0x04, 0x01, 0x01, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+static const uint8_t response[] = {0x04, 0x01, 0xfe, 0xff, 0x01, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
+
+namespace test = openpower::virtual_pnor::test;
+
+int main()
+{
+ struct mbox_context *ctx;
+
+ system_set_reserved_size(MEM_SIZE);
+ system_set_mtd_sizes(MEM_SIZE, ERASE_SIZE);
+
+ ctx = mbox_create_test_context(N_WINDOWS, WINDOW_SIZE);
+
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+ root.write("HBB", data, sizeof(data));
+
+ init_vpnor_from_paths(ctx);
+
+ int rc = mbox_command_dispatch(ctx, get_info, sizeof(get_info));
+ assert(rc == 1);
+
+ // send the request for partition1
+ rc = mbox_command_dispatch(ctx, create_read_window,
+ sizeof(create_read_window));
+ assert(rc == 1);
+
+ rc = mbox_cmp(ctx, response, sizeof(response));
+ assert(rc == 0);
+
+ // Compare the reserved memory to the pnor
+ rc = memcmp(ctx->mem, data, 6);
+ assert(rc == 0);
+
+ return rc;
+}
diff --git a/vpnor/test/create_read_window_partition_invalid.cpp b/vpnor/test/create_read_window_partition_invalid.cpp
new file mode 100644
index 0000000..9ed4347
--- /dev/null
+++ b/vpnor/test/create_read_window_partition_invalid.cpp
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include <assert.h>
+#include <string.h>
+
+#include "config.h"
+#include "vpnor/mboxd_pnor_partition_table.h"
+
+extern "C" {
+#include "test/mbox.h"
+#include "test/system.h"
+}
+
+#include "vpnor/test/tmpd.hpp"
+
+const std::string toc[] = {
+ "partition01=HBB,00002000,00003000,80,ECC,READONLY",
+};
+
+static constexpr auto BLOCK_SIZE = 4096;
+static constexpr auto MEM_SIZE = BLOCK_SIZE * 2;
+static constexpr auto ERASE_SIZE = BLOCK_SIZE;
+static constexpr auto N_WINDOWS = 1;
+static constexpr auto WINDOW_SIZE = BLOCK_SIZE;
+
+static const uint8_t get_info[] = {0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+/* Request access below the specified partition */
+static const uint8_t create_read_window[] = {0x04, 0x01, 0x01, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+int main()
+{
+ namespace test = openpower::virtual_pnor::test;
+
+ struct mbox_context *ctx;
+ int rc;
+
+ system_set_reserved_size(MEM_SIZE);
+ system_set_mtd_sizes(MEM_SIZE, ERASE_SIZE);
+
+ ctx = mbox_create_test_context(N_WINDOWS, WINDOW_SIZE);
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+ init_vpnor_from_paths(ctx);
+
+ rc = mbox_command_dispatch(ctx, get_info, sizeof(get_info));
+ assert(rc == 1);
+
+ rc = mbox_command_dispatch(ctx, create_read_window,
+ sizeof(create_read_window));
+ return !(rc == 1);
+}
diff --git a/vpnor/test/create_read_window_remap.cpp b/vpnor/test/create_read_window_remap.cpp
new file mode 100644
index 0000000..ea319c1
--- /dev/null
+++ b/vpnor/test/create_read_window_remap.cpp
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include <assert.h>
+#include <experimental/filesystem>
+#include <fstream>
+#include <string.h>
+#include <vector>
+
+#include "config.h"
+#include "vpnor/mboxd_pnor_partition_table.h"
+
+extern "C" {
+#include "test/mbox.h"
+#include "test/system.h"
+}
+
+#include "vpnor/test/tmpd.hpp"
+
+static const auto BLOCK_SIZE = 4096;
+static const auto ERASE_SIZE = BLOCK_SIZE;
+static const auto WINDOW_SIZE = 16 * BLOCK_SIZE;
+static const auto N_WINDOWS = 2;
+static const auto MEM_SIZE = N_WINDOWS * WINDOW_SIZE;
+
+const std::string toc[] = {
+ "partition01=ONE,00001000,00011000,80,ECC,READONLY",
+};
+
+static const uint8_t get_info[] = {0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+namespace test = openpower::virtual_pnor::test;
+
+int main()
+{
+ uint8_t request[] = {0x04, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ uint8_t response[] = {0x04, 0x01, 0xe0, 0xff, 0x10, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
+
+ struct mbox_context *ctx;
+
+ system_set_reserved_size(MEM_SIZE);
+ system_set_mtd_sizes(MEM_SIZE, ERASE_SIZE);
+
+ ctx = mbox_create_test_context(N_WINDOWS, WINDOW_SIZE);
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+ init_vpnor_from_paths(ctx);
+
+ int rc = mbox_command_dispatch(ctx, get_info, sizeof(get_info));
+ assert(rc == 1);
+
+ for (int i = 1; i < (0x10000 / BLOCK_SIZE); i++)
+ {
+ /* Update the requested offset */
+ put_u16(&request[2], i);
+
+ /*
+ * Reuse the offset as a sequence number, because it's unique. Request
+ * and response have the same sequence number
+ */
+ request[1] = i;
+ response[1] = i;
+
+ rc = mbox_command_dispatch(ctx, request, sizeof(request));
+ assert(rc == 1);
+
+ /* Check that it maps to the same window each time */
+ rc = mbox_cmp(ctx, response, sizeof(response));
+ assert(rc == 0);
+ }
+
+ return 0;
+}
diff --git a/vpnor/test/create_read_window_size.cpp b/vpnor/test/create_read_window_size.cpp
new file mode 100644
index 0000000..1837546
--- /dev/null
+++ b/vpnor/test/create_read_window_size.cpp
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include <assert.h>
+#include <experimental/filesystem>
+
+#include "config.h"
+#include "vpnor/mboxd_pnor_partition_table.h"
+
+extern "C" {
+#include "test/mbox.h"
+#include "test/system.h"
+}
+
+#include "vpnor/test/tmpd.hpp"
+static const auto BLOCK_SIZE = 4096;
+static const auto ERASE_SIZE = BLOCK_SIZE;
+static const auto WINDOW_SIZE = 2 * BLOCK_SIZE;
+static const auto MEM_SIZE = WINDOW_SIZE;
+static const auto N_WINDOWS = 1;
+static const auto PNOR_SIZE = 4 * BLOCK_SIZE;
+
+const std::string toc[] = {
+ "partition01=ONE,00001000,00002000,80,ECC,READONLY",
+ "partition02=TWO,00002000,00004000,80,ECC,READONLY",
+};
+
+static const uint8_t get_info[] = {0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+static const uint8_t request_one[] = {0x04, 0x01, 0x01, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+static const uint8_t response_one[] = {0x04, 0x01, 0xfe, 0xff, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01};
+
+static const uint8_t request_two[] = {0x04, 0x02, 0x02, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+static const uint8_t response_two[] = {0x04, 0x02, 0xfe, 0xff, 0x02,
+ 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01};
+
+namespace test = openpower::virtual_pnor::test;
+
+int main()
+{
+ struct mbox_context *ctx;
+
+ system_set_reserved_size(MEM_SIZE);
+ system_set_mtd_sizes(PNOR_SIZE, ERASE_SIZE);
+
+ ctx = mbox_create_test_context(N_WINDOWS, WINDOW_SIZE);
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+ init_vpnor_from_paths(ctx);
+
+ int rc = mbox_command_dispatch(ctx, get_info, sizeof(get_info));
+ assert(rc == 1);
+
+ rc = mbox_command_dispatch(ctx, request_one, sizeof(request_one));
+ assert(rc == 1);
+
+ rc = mbox_cmp(ctx, response_one, sizeof(response_one));
+ assert(rc == 0);
+
+ rc = mbox_command_dispatch(ctx, request_two, sizeof(request_two));
+ assert(rc == 1);
+
+ rc = mbox_cmp(ctx, response_two, sizeof(response_two));
+ assert(rc == 0);
+
+ return rc;
+}
diff --git a/vpnor/test/create_read_window_straddle_partitions.cpp b/vpnor/test/create_read_window_straddle_partitions.cpp
new file mode 100644
index 0000000..e396088
--- /dev/null
+++ b/vpnor/test/create_read_window_straddle_partitions.cpp
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "vpnor/mboxd_pnor_partition_table.h"
+
+extern "C" {
+#include "test/mbox.h"
+#include "test/system.h"
+}
+
+#include "vpnor/test/tmpd.hpp"
+
+const std::string toc[] = {
+ "partition01=ONE,00001000,00002000,80,ECC,READONLY",
+ "partition02=TWO,00002000,00003000,80,ECC,READONLY",
+};
+
+uint8_t data[8] = {0xaa, 0x55, 0xaa, 0x66, 0x77, 0x88, 0x99, 0xab};
+
+static constexpr auto BLOCK_SIZE = 0x1000;
+static constexpr auto MEM_SIZE = BLOCK_SIZE * 2;
+static constexpr auto ERASE_SIZE = BLOCK_SIZE;
+static constexpr auto N_WINDOWS = 1;
+static constexpr auto WINDOW_SIZE = MEM_SIZE;
+static constexpr auto PNOR_SIZE = MEM_SIZE * 2;
+
+static const uint8_t get_info[] = {0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+static const uint8_t create_read_window[] = {0x04, 0x01, 0x01, 0x00, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+static const uint8_t response[] = {
+ 0x04, 0x01, 0xfe, 0xff, 0x01, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+};
+
+int main()
+{
+ namespace test = openpower::virtual_pnor::test;
+ namespace fs = std::experimental::filesystem;
+
+ struct mbox_context *ctx;
+
+ system_set_reserved_size(MEM_SIZE);
+ system_set_mtd_sizes(PNOR_SIZE, ERASE_SIZE);
+
+ ctx = mbox_create_test_context(N_WINDOWS, WINDOW_SIZE);
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+ init_vpnor_from_paths(ctx);
+
+ int rc = mbox_command_dispatch(ctx, get_info, sizeof(get_info));
+ assert(rc == 1);
+
+ // Request a read window that would cover both partitions. With the current
+ // behaviour, we expect to receive a reply describing a window that covers
+ // the first partition but is limited in size to exclude the second
+ // partition.
+ rc = mbox_command_dispatch(ctx, create_read_window,
+ sizeof(create_read_window));
+ assert(rc == 1);
+
+ rc = mbox_cmp(ctx, response, sizeof(response));
+ assert(rc == 0);
+
+ return 0;
+}
diff --git a/vpnor/test/create_read_window_toc.cpp b/vpnor/test/create_read_window_toc.cpp
new file mode 100644
index 0000000..32f6523
--- /dev/null
+++ b/vpnor/test/create_read_window_toc.cpp
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+#include <assert.h>
+#include <sys/mman.h>
+#include <string.h>
+
+#include "config.h"
+#include "vpnor/pnor_partition_table.hpp"
+
+extern "C" {
+#include "test/mbox.h"
+#include "test/system.h"
+}
+
+#include "vpnor/test/tmpd.hpp"
+
+static constexpr auto BLOCK_SIZE = 4 * 1024;
+static constexpr auto PNOR_SIZE = 64 * 1024 * 1024;
+static constexpr auto MEM_SIZE = BLOCK_SIZE * 2;
+static constexpr auto ERASE_SIZE = BLOCK_SIZE;
+static constexpr auto N_WINDOWS = 1;
+static constexpr auto WINDOW_SIZE = BLOCK_SIZE;
+static constexpr auto TOC_PART_SIZE = BLOCK_SIZE;
+
+const std::string toc[] = {
+ "partition00=part,00000000,00001000,80,READONLY",
+ "partition01=ONE,00001000,00002000,80,READWRITE",
+};
+
+static const uint8_t get_info[] = {0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+/* Request access to the ToC base for one block */
+static const uint8_t create_read_window[] = {0x04, 0x01, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+/* Expect a response containing the ToC in one block */
+static const uint8_t response[] = {
+ 0x04, 0x01, 0xfe, 0xff, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+};
+
+int main()
+{
+ namespace test = openpower::virtual_pnor::test;
+ namespace vpnor = openpower::virtual_pnor;
+
+ struct mbox_context* ctx;
+ int rc;
+
+ system_set_reserved_size(MEM_SIZE);
+ system_set_mtd_sizes(PNOR_SIZE, ERASE_SIZE);
+
+ ctx = mbox_create_test_context(N_WINDOWS, WINDOW_SIZE);
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+ vpnor::partition::Table table(ctx);
+
+ /* Make sure the ToC exactly fits in the space allocated for it */
+ assert(table.capacity() == TOC_PART_SIZE);
+
+ init_vpnor_from_paths(ctx);
+
+ rc = mbox_command_dispatch(ctx, get_info, sizeof(get_info));
+ assert(rc == 1);
+
+ rc = mbox_command_dispatch(ctx, create_read_window,
+ sizeof(create_read_window));
+ assert(rc == 1);
+
+ rc = mbox_cmp(ctx, response, sizeof(response));
+ assert(rc == 0);
+
+ /* Ensure our partition table is present and as expected */
+ const pnor_partition_table& toc = table.getHostTable();
+ rc = memcmp(ctx->mem, &toc, table.size());
+ assert(rc == 0);
+
+ return 0;
+}
diff --git a/vpnor/test/create_write_window_ro_partition.cpp b/vpnor/test/create_write_window_ro_partition.cpp
new file mode 100644
index 0000000..09dbba0
--- /dev/null
+++ b/vpnor/test/create_write_window_ro_partition.cpp
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include <assert.h>
+
+#include "config.h"
+#include "vpnor/mboxd_pnor_partition_table.h"
+
+extern "C" {
+#include "test/mbox.h"
+#include "test/system.h"
+}
+
+#include "vpnor/test/tmpd.hpp"
+
+const std::string toc[] = {
+ "partition01=HBB,00001000,00002000,80,ECC,READONLY",
+};
+
+static const auto BLOCK_SIZE = 4096;
+static const auto MEM_SIZE = BLOCK_SIZE * 2;
+static const auto ERASE_SIZE = BLOCK_SIZE;
+static const auto N_WINDOWS = 1;
+static const auto WINDOW_SIZE = BLOCK_SIZE;
+
+static const uint8_t get_info[] = {0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+// offset 0x100 and size 6
+static const uint8_t create_write_window[] = {
+ 0x06, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const uint8_t response[] = {0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07};
+
+namespace test = openpower::virtual_pnor::test;
+
+int main()
+{
+ struct mbox_context *ctx;
+
+ system_set_reserved_size(MEM_SIZE);
+ system_set_mtd_sizes(MEM_SIZE, ERASE_SIZE);
+
+ ctx = mbox_create_test_context(N_WINDOWS, WINDOW_SIZE);
+
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+
+ init_vpnor_from_paths(ctx);
+
+ int rc = mbox_command_dispatch(ctx, get_info, sizeof(get_info));
+ assert(rc == 1);
+
+ rc = mbox_command_dispatch(ctx, create_write_window,
+ sizeof(create_write_window));
+ assert(rc == 7);
+
+ rc = mbox_cmp(ctx, response, sizeof(response));
+ assert(rc == 0);
+
+ return rc;
+}
diff --git a/vpnor/test/create_write_window_rw_partition.cpp b/vpnor/test/create_write_window_rw_partition.cpp
new file mode 100644
index 0000000..74b5831
--- /dev/null
+++ b/vpnor/test/create_write_window_rw_partition.cpp
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include <assert.h>
+
+#include "config.h"
+#include "vpnor/mboxd_pnor_partition_table.h"
+
+extern "C" {
+#include "test/mbox.h"
+#include "test/system.h"
+}
+
+#include "vpnor/test/tmpd.hpp"
+
+const std::string toc[] = {
+ "partition01=HBB,00001000,00002000,80,ECC,READWRITE",
+};
+
+static const auto BLOCK_SIZE = 4096;
+static const auto MEM_SIZE = BLOCK_SIZE * 2;
+static const auto ERASE_SIZE = BLOCK_SIZE;
+static const auto N_WINDOWS = 1;
+static const auto WINDOW_SIZE = BLOCK_SIZE;
+
+static const uint8_t get_info[] = {0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+// offset 0x100 and size 6
+static const uint8_t create_write_window[] = {
+ 0x06, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const uint8_t response[] = {0x06, 0x01, 0xfe, 0xff, 0x01, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
+
+namespace test = openpower::virtual_pnor::test;
+
+int main()
+{
+ struct mbox_context *ctx;
+
+ system_set_reserved_size(MEM_SIZE);
+ system_set_mtd_sizes(MEM_SIZE, ERASE_SIZE);
+
+ ctx = mbox_create_test_context(N_WINDOWS, WINDOW_SIZE);
+
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+
+ init_vpnor_from_paths(ctx);
+
+ int rc = mbox_command_dispatch(ctx, get_info, sizeof(get_info));
+ assert(rc == 1);
+
+ rc = mbox_command_dispatch(ctx, create_write_window,
+ sizeof(create_write_window));
+ assert(rc == 1);
+
+ rc = mbox_cmp(ctx, response, sizeof(response));
+ assert(rc == 0);
+
+ return rc;
+}
diff --git a/vpnor/test/create_write_window_unmapped.cpp b/vpnor/test/create_write_window_unmapped.cpp
new file mode 100644
index 0000000..47ba57e
--- /dev/null
+++ b/vpnor/test/create_write_window_unmapped.cpp
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include <assert.h>
+
+#include "config.h"
+#include "vpnor/mboxd_pnor_partition_table.h"
+
+extern "C" {
+#include "test/mbox.h"
+#include "test/system.h"
+}
+
+#include "vpnor/test/tmpd.hpp"
+
+static constexpr auto BLOCK_SIZE = 0x1000;
+static constexpr auto ERASE_SIZE = BLOCK_SIZE;
+static constexpr auto N_WINDOWS = 1;
+static constexpr auto WINDOW_SIZE = BLOCK_SIZE;
+static constexpr auto MEM_SIZE = WINDOW_SIZE;
+static constexpr auto PNOR_SIZE = 3 * BLOCK_SIZE;
+
+const std::string toc[] = {
+ "partition01=HBB,00001000,00002000,80,ECC,READWRITE",
+};
+
+static const uint8_t get_info[] = {0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+// offset 0x100 and size 6
+static const uint8_t create_write_window[] = {
+ 0x06, 0x01, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static const uint8_t response[] = {0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07};
+
+namespace test = openpower::virtual_pnor::test;
+
+int main()
+{
+ struct mbox_context *ctx;
+
+ system_set_reserved_size(MEM_SIZE);
+ system_set_mtd_sizes(PNOR_SIZE, ERASE_SIZE);
+
+ ctx = mbox_create_test_context(N_WINDOWS, WINDOW_SIZE);
+
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+
+ init_vpnor_from_paths(ctx);
+
+ int rc = mbox_command_dispatch(ctx, get_info, sizeof(get_info));
+ assert(rc == MBOX_R_SUCCESS);
+
+ rc = mbox_command_dispatch(ctx, create_write_window,
+ sizeof(create_write_window));
+ assert(rc == MBOX_R_WINDOW_ERROR);
+
+ rc = mbox_cmp(ctx, response, sizeof(response));
+ assert(rc == 0);
+
+ return rc;
+}
diff --git a/vpnor/test/dump_flash.cpp b/vpnor/test/dump_flash.cpp
new file mode 100644
index 0000000..e811f6f
--- /dev/null
+++ b/vpnor/test/dump_flash.cpp
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include <assert.h>
+#include <string.h>
+
+#include "config.h"
+#include "mboxd_msg.h"
+#include "vpnor/mboxd_pnor_partition_table.h"
+
+extern "C" {
+#include "test/mbox.h"
+#include "test/system.h"
+}
+
+#include "vpnor/test/tmpd.hpp"
+
+struct test_context
+{
+ uint8_t seq;
+ struct mbox_context *ctx;
+};
+
+// Configure the system and the paritions such that we eventually request a
+// window that covers the last section of flash, but the remaining flash is
+// smaller than the window size
+static constexpr auto BLOCK_SIZE = 4096;
+static constexpr auto ERASE_SIZE = BLOCK_SIZE;
+static constexpr auto N_WINDOWS = 3;
+static constexpr auto WINDOW_SIZE = 2 * BLOCK_SIZE;
+static constexpr auto MEM_SIZE = N_WINDOWS * WINDOW_SIZE;
+static constexpr auto PNOR_SIZE = (4 * BLOCK_SIZE);
+
+const std::string toc[] = {
+ "partition01=ONE,00001000,00003000,80,ECC,READONLY",
+};
+
+static const uint8_t get_info[] = {0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+static constexpr auto MBOX_CREATE_READ_WINDOW = 4;
+
+static int mbox_create_read_window(struct test_context *tctx, size_t offset,
+ size_t len)
+{
+ union mbox_regs regs;
+
+ memset(&regs, 0, sizeof(regs));
+ regs.msg.command = MBOX_CREATE_READ_WINDOW;
+ regs.msg.seq = ++tctx->seq;
+ put_u16(&regs.msg.args[0], offset);
+ put_u16(&regs.msg.args[2], len);
+
+ return mbox_command_dispatch(tctx->ctx, regs.raw, sizeof(regs.raw));
+}
+
+int main()
+{
+ namespace test = openpower::virtual_pnor::test;
+
+ struct test_context _tctx = {0}, *tctx = &_tctx;
+ size_t len;
+ size_t pos;
+ int rc;
+
+ system_set_reserved_size(MEM_SIZE);
+ system_set_mtd_sizes(PNOR_SIZE, ERASE_SIZE);
+
+ tctx->ctx = mbox_create_test_context(N_WINDOWS, WINDOW_SIZE);
+ test::VpnorRoot root(tctx->ctx, toc, BLOCK_SIZE);
+ init_vpnor_from_paths(tctx->ctx);
+
+ rc = mbox_command_dispatch(tctx->ctx, get_info, sizeof(get_info));
+ assert(rc == 1);
+
+ pos = 0;
+ while (pos < (PNOR_SIZE / BLOCK_SIZE))
+ {
+ struct mbox_msg _msg, *msg = &_msg;
+
+ rc = mbox_create_read_window(tctx, pos, (WINDOW_SIZE / BLOCK_SIZE));
+ assert(rc == 1);
+
+ mbox_rspcpy(tctx->ctx, msg);
+
+ len = get_u16(&msg->args[2]);
+ pos = get_u16(&msg->args[4]) + len;
+ }
+
+ return 0;
+}
diff --git a/vpnor/test/read_patch.cpp b/vpnor/test/read_patch.cpp
new file mode 100644
index 0000000..31a422e
--- /dev/null
+++ b/vpnor/test/read_patch.cpp
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include "config.h"
+#include "common.h"
+#include "vpnor/mboxd_pnor_partition_table.h"
+
+#include <assert.h>
+
+extern "C" {
+#include "test/mbox.h"
+#include "test/system.h"
+}
+
+#include "vpnor/test/tmpd.hpp"
+
+static constexpr auto BLOCK_SIZE = 0x1000;
+static constexpr auto ERASE_SIZE = BLOCK_SIZE;
+static constexpr auto PART_SIZE = BLOCK_SIZE * 4;
+static constexpr auto PATCH_SIZE = PART_SIZE / 2;
+static constexpr auto N_WINDOWS = 2;
+static constexpr auto WINDOW_SIZE = PART_SIZE * 8;
+static constexpr auto MEM_SIZE = WINDOW_SIZE * N_WINDOWS;
+static constexpr auto PNOR_SIZE = MEM_SIZE * 2;
+
+const std::string toc[] = {
+ "partition01=ONE,00001000,00005000,80,ECC,READONLY",
+};
+
+static const uint8_t get_info[] = {0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+static const uint8_t create_read_window[] = {0x04, 0x01, 0x01, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+static const uint8_t response[] = {0x04, 0x01, 0xc0, 0xff, 0x04, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
+
+int main()
+{
+ namespace test = openpower::virtual_pnor::test;
+
+ struct mbox_context *ctx;
+
+ system_set_reserved_size(MEM_SIZE);
+ system_set_mtd_sizes(PNOR_SIZE, ERASE_SIZE);
+ ctx = mbox_create_test_context(N_WINDOWS, WINDOW_SIZE);
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+
+ // PATCH_SIZE is smaller than the size of the partition we defined. This
+ // test ensures that mboxd will behave correctly when we request an offset
+ // that is beyond the size of the backing file, but is in the set of valid
+ // offsets for the partition as defined by the ToC.
+ std::vector<uint8_t> patch(PATCH_SIZE, 0xff);
+ root.patch("ONE", patch.data(), patch.size());
+
+ init_vpnor_from_paths(ctx);
+
+ int rc = mbox_command_dispatch(ctx, get_info, sizeof(get_info));
+ assert(rc == 1);
+
+ rc = mbox_command_dispatch(ctx, create_read_window,
+ sizeof(create_read_window));
+ assert(rc == 1);
+
+ rc = mbox_cmp(ctx, response, sizeof(response));
+ assert(rc == 0);
+
+ return 0;
+}
diff --git a/vpnor/test/tmpd.cpp b/vpnor/test/tmpd.cpp
new file mode 100644
index 0000000..723bf56
--- /dev/null
+++ b/vpnor/test/tmpd.cpp
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include "vpnor/test/tmpd.hpp"
+
+namespace openpower
+{
+namespace virtual_pnor
+{
+namespace test
+{
+
+namespace fs = std::experimental::filesystem;
+
+size_t VpnorRoot::write(const std::string &name, const void *data, size_t len)
+{
+ // write() is for test environment setup - always write to ro section
+ fs::path path = root / "ro" / name;
+
+ if (!fs::exists(path))
+ /* It's not in the ToC */
+ throw std::invalid_argument(name);
+
+ std::ofstream(path).write((const char *)data, len);
+
+ return len;
+}
+
+size_t VpnorRoot::patch(const std::string &name, const void *data, size_t len)
+{
+ if (!fs::exists(root / "ro" / name))
+ /* It's not in the ToC */
+ throw std::invalid_argument(name);
+
+ std::ofstream(root / "patch" / name).write((const char *)data, len);
+
+ return len;
+}
+
+} // test
+} // virtual_pnor
+} // openpower
diff --git a/vpnor/test/tmpd.hpp b/vpnor/test/tmpd.hpp
new file mode 100644
index 0000000..45260ca
--- /dev/null
+++ b/vpnor/test/tmpd.hpp
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+/* Copyright (C) 2018 IBM Corp. */
+
+#include <assert.h>
+#include <string.h>
+#include <vector>
+#include <fstream>
+#include <experimental/filesystem>
+
+#include "config.h"
+#include "mbox.h"
+#include "vpnor/pnor_partition_table.hpp"
+
+namespace openpower
+{
+namespace virtual_pnor
+{
+namespace test
+{
+
+namespace fs = std::experimental::filesystem;
+
+class VpnorRoot
+{
+ public:
+ template <std::size_t N>
+ VpnorRoot(struct mbox_context* ctx, const std::string (&toc)[N],
+ size_t blockSize)
+ {
+ char tmplt[] = "/tmp/vpnor_root.XXXXXX";
+ char* tmpdir = mkdtemp(tmplt);
+ root = fs::path{tmpdir};
+
+ for (const auto& attr : attributes)
+ {
+ fs::create_directory(root / attr);
+ }
+
+ fs::path tocFilePath = root / "ro" / PARTITION_TOC_FILE;
+
+ for (const std::string& line : toc)
+ {
+ pnor_partition part;
+
+ openpower::virtual_pnor::parseTocLine(line, blockSize, part);
+
+ /* Populate the partition in the tree */
+ std::vector<char> zeroed(part.data.actual, 0);
+ fs::path partitionFilePath = root / "ro" / part.data.name;
+ std::ofstream(partitionFilePath)
+ .write(zeroed.data(), zeroed.size());
+
+ /* Update the ToC if the partition file was created */
+ std::ofstream(tocFilePath, std::ofstream::app) << line << "\n";
+ }
+
+ strncpy(ctx->paths.ro_loc, ro().c_str(), PATH_MAX - 1);
+ ctx->paths.ro_loc[PATH_MAX - 1] = '\0';
+ strncpy(ctx->paths.rw_loc, rw().c_str(), PATH_MAX - 1);
+ ctx->paths.rw_loc[PATH_MAX - 1] = '\0';
+ strncpy(ctx->paths.prsv_loc, prsv().c_str(), PATH_MAX - 1);
+ ctx->paths.prsv_loc[PATH_MAX - 1] = '\0';
+ strncpy(ctx->paths.patch_loc, patch().c_str(), PATH_MAX - 1);
+ ctx->paths.patch_loc[PATH_MAX - 1] = '\0';
+ }
+
+ VpnorRoot(const VpnorRoot&) = delete;
+ VpnorRoot& operator=(const VpnorRoot&) = delete;
+ VpnorRoot(VpnorRoot&&) = delete;
+ VpnorRoot& operator=(VpnorRoot&&) = delete;
+
+ ~VpnorRoot()
+ {
+ fs::remove_all(root);
+ }
+ fs::path ro()
+ {
+ return fs::path{root} / "ro";
+ }
+ fs::path rw()
+ {
+ return fs::path{root} / "rw";
+ }
+ fs::path prsv()
+ {
+ return fs::path{root} / "prsv";
+ }
+ fs::path patch()
+ {
+ return fs::path{root} / "patch";
+ }
+ size_t write(const std::string& name, const void* data, size_t len);
+ size_t patch(const std::string& name, const void* data, size_t len);
+
+ private:
+ fs::path root;
+ const std::string attributes[4] = {"ro", "rw", "prsv", "patch"};
+};
+
+} // test
+} // virtual_pnor
+} // openpower
diff --git a/vpnor/test/toc_flags.cpp b/vpnor/test/toc_flags.cpp
new file mode 100644
index 0000000..c30f7ad
--- /dev/null
+++ b/vpnor/test/toc_flags.cpp
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include "config.h"
+#include <assert.h>
+
+#include "common.h"
+#include "vpnor/pnor_partition_defs.h"
+#include "vpnor/pnor_partition_table.hpp"
+
+static constexpr auto BLOCK_SIZE = 4 * 1024;
+static constexpr auto DATA_MASK = ((1 << 24) - 1);
+
+int main()
+{
+ namespace vpnor = openpower::virtual_pnor;
+
+ struct pnor_partition part;
+ std::string line;
+
+ mbox_vlog = mbox_log_console;
+ verbosity = MBOX_LOG_DEBUG;
+
+ line = "partition01=FOO,00001000,00002000,80,ECC";
+ vpnor::parseTocLine(line, BLOCK_SIZE, part);
+ assert((part.data.user.data[0]) == PARTITION_ECC_PROTECTED);
+ assert(!(part.data.user.data[1] & DATA_MASK));
+
+ line = "partition01=FOO,00001000,00002000,80,PRESERVED";
+ vpnor::parseTocLine(line, BLOCK_SIZE, part);
+ assert(!(part.data.user.data[0]));
+ assert((part.data.user.data[1] & DATA_MASK) == PARTITION_PRESERVED);
+
+ line = "partition01=FOO,00001000,00002000,80,READONLY";
+ vpnor::parseTocLine(line, BLOCK_SIZE, part);
+ assert(!(part.data.user.data[0]));
+ assert((part.data.user.data[1] & DATA_MASK) == PARTITION_READONLY);
+
+ /* BACKUP is unimplemented */
+ line = "partition01=FOO,00001000,00002000,80,BACKUP";
+ vpnor::parseTocLine(line, BLOCK_SIZE, part);
+ assert(!(part.data.user.data[0]));
+ assert(!(part.data.user.data[1] & DATA_MASK));
+
+ line = "partition01=FOO,00001000,00002000,80,REPROVISION";
+ vpnor::parseTocLine(line, BLOCK_SIZE, part);
+ assert(!(part.data.user.data[0]));
+ assert((part.data.user.data[1] & DATA_MASK) == PARTITION_REPROVISION);
+
+ line = "partition01=FOO,00001000,00002000,80,VOLATILE";
+ vpnor::parseTocLine(line, BLOCK_SIZE, part);
+ assert(!(part.data.user.data[0]));
+ assert((part.data.user.data[1] & DATA_MASK) == PARTITION_VOLATILE);
+
+ line = "partition01=FOO,00001000,00002000,80,CLEARECC";
+ vpnor::parseTocLine(line, BLOCK_SIZE, part);
+ assert(!(part.data.user.data[0]));
+ assert((part.data.user.data[1] & DATA_MASK) == PARTITION_CLEARECC);
+
+ line = "partition01=FOO,00001000,00002000,80,READWRITE";
+ vpnor::parseTocLine(line, BLOCK_SIZE, part);
+ assert(!(part.data.user.data[0]));
+ assert(((part.data.user.data[1] & DATA_MASK) ^ PARTITION_READONLY) ==
+ PARTITION_READONLY);
+
+ line = "partition01=FOO,00001000,00002000,80,";
+ vpnor::parseTocLine(line, BLOCK_SIZE, part);
+ assert(!(part.data.user.data[0]));
+ assert(!(part.data.user.data[1] & DATA_MASK));
+
+ line = "partition01=FOO,00001000,00002000,80,junk";
+ vpnor::parseTocLine(line, BLOCK_SIZE, part);
+ assert(!(part.data.user.data[0]));
+ assert(!(part.data.user.data[1] & DATA_MASK));
+
+ return 0;
+}
diff --git a/vpnor/test/toc_lookup_failed.cpp b/vpnor/test/toc_lookup_failed.cpp
new file mode 100644
index 0000000..199a00b
--- /dev/null
+++ b/vpnor/test/toc_lookup_failed.cpp
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+#include <assert.h>
+#include <string.h>
+
+#include "config.h"
+#include "vpnor/pnor_partition_table.hpp"
+#include "xyz/openbmc_project/Common/error.hpp"
+
+extern "C" {
+#include "test/mbox.h"
+#include "test/system.h"
+}
+
+#include "vpnor/test/tmpd.hpp"
+
+static constexpr auto BLOCK_SIZE = 0x1000;
+static constexpr auto ERASE_SIZE = BLOCK_SIZE;
+static constexpr auto PNOR_SIZE = 64 * 1024 * 1024;
+static constexpr auto MEM_SIZE = 32 * 1024 * 1024;
+static constexpr auto N_WINDOWS = 1;
+static constexpr auto WINDOW_SIZE = BLOCK_SIZE * 2;
+
+const std::string toc[] = {
+ "partition01=ONE,00001000,00002000,80,",
+};
+
+int main()
+{
+ namespace err = sdbusplus::xyz::openbmc_project::Common::Error;
+ namespace test = openpower::virtual_pnor::test;
+ namespace vpnor = openpower::virtual_pnor;
+
+ struct mbox_context* ctx;
+
+ system_set_reserved_size(MEM_SIZE);
+ system_set_mtd_sizes(MEM_SIZE, ERASE_SIZE);
+
+ ctx = mbox_create_test_context(N_WINDOWS, WINDOW_SIZE);
+
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+ vpnor::partition::Table table(ctx);
+
+ try
+ {
+ table.partition("TWO");
+ }
+ catch (vpnor::UnknownPartition& e)
+ {
+ return 0;
+ }
+
+ assert(false);
+}
diff --git a/vpnor/test/toc_lookup_found.cpp b/vpnor/test/toc_lookup_found.cpp
new file mode 100644
index 0000000..411e3f8
--- /dev/null
+++ b/vpnor/test/toc_lookup_found.cpp
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+#include <assert.h>
+#include <string.h>
+
+#include "config.h"
+#include "vpnor/pnor_partition_table.hpp"
+
+extern "C" {
+#include "test/mbox.h"
+#include "test/system.h"
+}
+
+#include "vpnor/test/tmpd.hpp"
+
+static constexpr auto BLOCK_SIZE = 0x1000;
+static constexpr auto ERASE_SIZE = BLOCK_SIZE;
+static constexpr auto PNOR_SIZE = 64 * 1024 * 1024;
+static constexpr auto MEM_SIZE = 32 * 1024 * 1024;
+static constexpr auto N_WINDOWS = 1;
+static constexpr auto WINDOW_SIZE = BLOCK_SIZE * 2;
+
+const std::string toc[] = {
+ "partition01=ONE,00001000,00002000,80,",
+ "partition02=TWO,00002000,00004000,80,",
+ "partition03=THREE,00004000,00008000,80,",
+};
+
+int main()
+{
+ namespace test = openpower::virtual_pnor::test;
+ namespace vpnor = openpower::virtual_pnor;
+
+ struct mbox_context* ctx;
+
+ system_set_reserved_size(MEM_SIZE);
+ system_set_mtd_sizes(MEM_SIZE, ERASE_SIZE);
+
+ ctx = mbox_create_test_context(N_WINDOWS, WINDOW_SIZE);
+
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+ vpnor::partition::Table table(ctx);
+
+ const struct pnor_partition& part = table.partition("TWO");
+ assert(part.data.id == 2);
+ assert(part.data.base == 2);
+ assert(part.data.size == 2);
+
+ return 0;
+}
diff --git a/vpnor/test/toc_missing_file.cpp b/vpnor/test/toc_missing_file.cpp
new file mode 100644
index 0000000..821653f
--- /dev/null
+++ b/vpnor/test/toc_missing_file.cpp
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+#include <assert.h>
+#include <string.h>
+
+#include "config.h"
+#include "vpnor/pnor_partition_table.hpp"
+
+extern "C" {
+#include "test/mbox.h"
+#include "test/system.h"
+}
+
+#include "vpnor/test/tmpd.hpp"
+
+static constexpr auto BLOCK_SIZE = 0x1000;
+static constexpr auto ERASE_SIZE = BLOCK_SIZE;
+static constexpr auto PNOR_SIZE = 64 * 1024 * 1024;
+static constexpr auto MEM_SIZE = 32 * 1024 * 1024;
+static constexpr auto N_WINDOWS = 1;
+static constexpr auto WINDOW_SIZE = BLOCK_SIZE * 2;
+
+const std::string toc[] = {
+ "partition01=ONE,00001000,00002000,80,",
+ "partition02=TWO,00002000,00003000,80,",
+};
+
+int main()
+{
+ namespace test = openpower::virtual_pnor::test;
+ namespace fs = std::experimental::filesystem;
+ namespace vpnor = openpower::virtual_pnor;
+
+ struct mbox_context* ctx;
+
+ system_set_reserved_size(MEM_SIZE);
+ system_set_mtd_sizes(MEM_SIZE, ERASE_SIZE);
+
+ ctx = mbox_create_test_context(N_WINDOWS, WINDOW_SIZE);
+
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+
+ fs::remove(root.ro() / "TWO");
+
+ try
+ {
+ vpnor::partition::Table table(ctx);
+ }
+ catch (vpnor::InvalidTocEntry& e)
+ {
+ return 0;
+ }
+
+ assert(false);
+}
diff --git a/vpnor/test/toc_no_end.cpp b/vpnor/test/toc_no_end.cpp
new file mode 100644
index 0000000..f9c5187
--- /dev/null
+++ b/vpnor/test/toc_no_end.cpp
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include "config.h"
+#include <assert.h>
+
+#include "vpnor/pnor_partition_table.hpp"
+
+static constexpr auto BLOCK_SIZE = 4 * 1024;
+
+int main()
+{
+ namespace vpnor = openpower::virtual_pnor;
+
+ struct pnor_partition part;
+ std::string line;
+
+ line = "partition01=FOO,00001000,,80,ECC,PRESERVED";
+ try
+ {
+ openpower::virtual_pnor::parseTocLine(line, BLOCK_SIZE, part);
+ }
+ catch (vpnor::MalformedTocEntry& e)
+ {
+ return 0;
+ }
+
+ assert(false);
+}
diff --git a/vpnor/test/toc_no_name.cpp b/vpnor/test/toc_no_name.cpp
new file mode 100644
index 0000000..d62056f
--- /dev/null
+++ b/vpnor/test/toc_no_name.cpp
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include "config.h"
+#include <assert.h>
+
+#include "vpnor/pnor_partition_table.hpp"
+
+static constexpr auto BLOCK_SIZE = 4 * 1024;
+
+int main()
+{
+ namespace vpnor = openpower::virtual_pnor;
+
+ const std::string line = "partition01=,00000000,00000400,80,ECC,PRESERVED";
+ struct pnor_partition part;
+
+ try
+ {
+ vpnor::parseTocLine(line, BLOCK_SIZE, part);
+ }
+ catch (vpnor::MalformedTocEntry& e)
+ {
+ return 0;
+ }
+
+ assert(false);
+}
diff --git a/vpnor/test/toc_no_start.cpp b/vpnor/test/toc_no_start.cpp
new file mode 100644
index 0000000..1d20a46
--- /dev/null
+++ b/vpnor/test/toc_no_start.cpp
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include "config.h"
+#include <assert.h>
+
+#include "vpnor/pnor_partition_table.hpp"
+
+static constexpr auto BLOCK_SIZE = 4 * 1024;
+
+int main()
+{
+ namespace vpnor = openpower::virtual_pnor;
+
+ struct pnor_partition part;
+ std::string line;
+
+ line = "partition01=FOO,,00001000,80,ECC,PRESERVED";
+ try
+ {
+ openpower::virtual_pnor::parseTocLine(line, BLOCK_SIZE, part);
+ }
+ catch (vpnor::MalformedTocEntry& e)
+ {
+ return 0;
+ }
+
+ assert(false);
+}
diff --git a/vpnor/test/toc_no_version.cpp b/vpnor/test/toc_no_version.cpp
new file mode 100644
index 0000000..68cb057
--- /dev/null
+++ b/vpnor/test/toc_no_version.cpp
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include "config.h"
+#include <assert.h>
+
+#include "vpnor/pnor_partition_table.hpp"
+
+static constexpr auto BLOCK_SIZE = 4 * 1024;
+
+int main()
+{
+ namespace vpnor = openpower::virtual_pnor;
+
+ struct pnor_partition part;
+ std::string line;
+
+ line = "partition01=FOO,00001000,00002000,,ECC,PRESERVED";
+ try
+ {
+ openpower::virtual_pnor::parseTocLine(line, BLOCK_SIZE, part);
+ }
+ catch (vpnor::MalformedTocEntry& e)
+ {
+ return 0;
+ }
+
+ assert(false);
+}
diff --git a/vpnor/test/toc_overlap.cpp b/vpnor/test/toc_overlap.cpp
new file mode 100644
index 0000000..94d071c
--- /dev/null
+++ b/vpnor/test/toc_overlap.cpp
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+#include <assert.h>
+#include <string.h>
+
+#include "config.h"
+#include "vpnor/pnor_partition_table.hpp"
+
+extern "C" {
+#include "test/mbox.h"
+#include "test/system.h"
+}
+
+#include "vpnor/test/tmpd.hpp"
+
+static constexpr auto BLOCK_SIZE = 0x1000;
+static constexpr auto ERASE_SIZE = BLOCK_SIZE;
+static constexpr auto PNOR_SIZE = 64 * 1024 * 1024;
+static constexpr auto MEM_SIZE = 32 * 1024 * 1024;
+static constexpr auto N_WINDOWS = 1;
+static constexpr auto WINDOW_SIZE = BLOCK_SIZE * 2;
+
+const std::string toc[] = {
+ "partition01=ONE,00001000,00003000,80,",
+ "partition02=TWO,00002000,00004000,80,",
+};
+
+int main()
+{
+ namespace test = openpower::virtual_pnor::test;
+ namespace vpnor = openpower::virtual_pnor;
+
+ struct mbox_context* ctx;
+
+ system_set_reserved_size(MEM_SIZE);
+ system_set_mtd_sizes(MEM_SIZE, ERASE_SIZE);
+
+ ctx = mbox_create_test_context(N_WINDOWS, WINDOW_SIZE);
+
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+
+ try
+ {
+ vpnor::partition::Table table(ctx);
+ }
+ catch (vpnor::InvalidTocEntry& e)
+ {
+ return 0;
+ }
+
+ assert(false);
+}
diff --git a/vpnor/test/toc_start_gt_end.cpp b/vpnor/test/toc_start_gt_end.cpp
new file mode 100644
index 0000000..69edc63
--- /dev/null
+++ b/vpnor/test/toc_start_gt_end.cpp
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include "config.h"
+#include <assert.h>
+
+#include "vpnor/pnor_partition_table.hpp"
+
+static constexpr auto BLOCK_SIZE = 4 * 1024;
+
+int main()
+{
+ namespace vpnor = openpower::virtual_pnor;
+
+ std::string line = "partition01=FOO,00002000,00001000,80,ECC,PRESERVED";
+ pnor_partition part;
+
+ try
+ {
+ vpnor::parseTocLine(line, BLOCK_SIZE, part);
+ }
+ catch (vpnor::InvalidTocEntry& e)
+ {
+ return 0;
+ }
+
+ assert(false);
+}
diff --git a/vpnor/test/write_patch.cpp b/vpnor/test/write_patch.cpp
new file mode 100644
index 0000000..3b2b16a
--- /dev/null
+++ b/vpnor/test/write_patch.cpp
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include <assert.h>
+#include <experimental/filesystem>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/syslog.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "mbox.h"
+#include "mboxd_flash.h"
+
+#include "vpnor/test/tmpd.hpp"
+
+static constexpr auto BLOCK_SIZE = 0x1000;
+static constexpr auto DATA_SIZE = 8;
+
+const uint8_t data[DATA_SIZE] = {0xa0, 0xa1, 0xa2, 0xa3,
+ 0xa4, 0xa5, 0xa6, 0xa7};
+
+const std::string toc[] = {
+ "partition01=TEST1,00001000,00002000,80,ECC,READWRITE",
+};
+
+int main(void)
+{
+ namespace fs = std::experimental::filesystem;
+ namespace test = openpower::virtual_pnor::test;
+
+ struct mbox_context _ctx, *ctx = &_ctx;
+ char src[DATA_SIZE]{0};
+ void *map;
+ int rc;
+ int fd;
+
+ /* Setup */
+ memset(ctx, 0, sizeof(mbox_context));
+
+ mbox_vlog = &mbox_log_console;
+ verbosity = (verbose)2;
+
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+ root.write("TEST1", data, sizeof(data));
+ /* write_flash doesn't copy the file for us */
+ assert(fs::copy_file(root.ro() / "TEST1", root.rw() / "TEST1"));
+ fs::path patch = root.patch() / "TEST1";
+ assert(fs::copy_file(root.ro() / "TEST1", patch));
+
+ init_vpnor_from_paths(ctx);
+
+ /* Test */
+ memset(src, 0x33, sizeof(src));
+ rc = write_flash(ctx, 0x1000, src, sizeof(src));
+ assert(rc == 0);
+
+ /* Check that RW file is unmodified after the patch write */
+ fd = open((root.rw() / "TEST1").c_str(), O_RDONLY);
+ map = mmap(NULL, sizeof(src), PROT_READ, MAP_SHARED, fd, 0);
+ assert(map != MAP_FAILED);
+ rc = memcmp(data, map, sizeof(src));
+ assert(rc == 0);
+ munmap(map, sizeof(src));
+ close(fd);
+
+ /* Check that PATCH is modified with the new data */
+ fd = open(patch.c_str(), O_RDONLY);
+ map = mmap(NULL, sizeof(src), PROT_READ, MAP_SHARED, fd, 0);
+ assert(map != MAP_FAILED);
+ rc = memcmp(src, map, sizeof(src));
+ assert(rc == 0);
+ munmap(map, sizeof(src));
+ close(fd);
+
+ destroy_vpnor(ctx);
+ free(ctx->flash_bmap);
+
+ return rc;
+}
diff --git a/vpnor/test/write_patch_resize.cpp b/vpnor/test/write_patch_resize.cpp
new file mode 100644
index 0000000..8d67683
--- /dev/null
+++ b/vpnor/test/write_patch_resize.cpp
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include <assert.h>
+#include <experimental/filesystem>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/syslog.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "mbox.h"
+#include "mboxd_flash.h"
+
+#include "vpnor/test/tmpd.hpp"
+
+static constexpr auto BLOCK_SIZE = 0x1000;
+static constexpr auto PART_SIZE = BLOCK_SIZE;
+static constexpr auto PATCH_SIZE = BLOCK_SIZE / 2;
+static constexpr auto UPDATE_SIZE = BLOCK_SIZE;
+
+const std::string toc[] = {
+ "partition01=TEST1,00001000,00002000,80,ECC,READWRITE",
+};
+
+int main(void)
+{
+ namespace fs = std::experimental::filesystem;
+ namespace test = openpower::virtual_pnor::test;
+
+ struct mbox_context _ctx, *ctx = &_ctx;
+ void *map;
+ int rc;
+ int fd;
+
+ /* Setup */
+ memset(ctx, 0, sizeof(mbox_context));
+
+ mbox_vlog = &mbox_log_console;
+ verbosity = (verbose)2;
+
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+ std::vector<uint8_t> roContent(PART_SIZE, 0xff);
+ root.write("TEST1", roContent.data(), roContent.size());
+ /* write_flash doesn't copy the file for us */
+ std::vector<uint8_t> patchContent(PATCH_SIZE, 0xaa);
+ root.patch("TEST1", patchContent.data(), patchContent.size());
+
+ init_vpnor_from_paths(ctx);
+
+ /* Test */
+ std::vector<uint8_t> update(UPDATE_SIZE, 0x55);
+ rc = write_flash(ctx, 0x1000, update.data(), update.size());
+ assert(rc == 0);
+
+ /* Check that PATCH is modified with the new data */
+ fs::path patch = root.patch() / "TEST1";
+ assert(UPDATE_SIZE == fs::file_size(patch));
+ fd = open(patch.c_str(), O_RDONLY);
+ map = mmap(NULL, UPDATE_SIZE, PROT_READ, MAP_SHARED, fd, 0);
+ assert(map != MAP_FAILED);
+ rc = memcmp(update.data(), map, update.size());
+ assert(rc == 0);
+ munmap(map, update.size());
+ close(fd);
+
+ destroy_vpnor(ctx);
+ free(ctx->flash_bmap);
+
+ return rc;
+}
diff --git a/vpnor/test/write_prsv.cpp b/vpnor/test/write_prsv.cpp
new file mode 100644
index 0000000..26f1d86
--- /dev/null
+++ b/vpnor/test/write_prsv.cpp
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include <assert.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "mbox.h"
+#include "mboxd_flash.h"
+
+#include "vpnor/test/tmpd.hpp"
+
+static constexpr auto BLOCK_SIZE = 0x1000;
+
+const std::string toc[] = {
+ "partition01=TEST1,00001000,00002000,80,ECC,PRESERVED",
+};
+
+namespace test = openpower::virtual_pnor::test;
+
+int main(void)
+{
+ namespace fs = std::experimental::filesystem;
+
+ struct mbox_context _ctx, *ctx = &_ctx;
+ uint8_t src[8];
+ void *map;
+ int fd;
+ int rc;
+
+ /* Setup */
+ memset(ctx, 0, sizeof(mbox_context));
+
+ mbox_vlog = &mbox_log_console;
+ verbosity = (verbose)2;
+
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+ init_vpnor_from_paths(ctx);
+
+ /* Test */
+ memset(src, 0xaa, sizeof(src));
+ rc = write_flash(ctx, 0x1000, src, sizeof(src));
+ assert(rc == 0);
+
+ /* Verify */
+ fd = open((root.prsv() / "TEST1").c_str(), O_RDONLY);
+ assert(fd >= 0);
+ map = mmap(NULL, sizeof(src), PROT_READ, MAP_PRIVATE, fd, 0);
+ assert(map != MAP_FAILED);
+
+ rc = memcmp(src, map, sizeof(src));
+ assert(rc == 0);
+ munmap(map, sizeof(src));
+ close(fd);
+
+ /* Cleanup */
+ destroy_vpnor(ctx);
+
+ return 0;
+}
diff --git a/vpnor/test/write_ro.cpp b/vpnor/test/write_ro.cpp
new file mode 100644
index 0000000..53eeb18
--- /dev/null
+++ b/vpnor/test/write_ro.cpp
@@ -0,0 +1,50 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include <assert.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "mbox.h"
+#include "mboxd_flash.h"
+
+#include "vpnor/test/tmpd.hpp"
+
+static constexpr auto BLOCK_SIZE = 0x1000;
+
+const std::string toc[] = {
+ "partition01=TEST1,00001000,00002000,80,ECC,READONLY",
+};
+
+int main(void)
+{
+ namespace fs = std::experimental::filesystem;
+ namespace test = openpower::virtual_pnor::test;
+
+ struct mbox_context _ctx, *ctx = &_ctx;
+ uint8_t src[8] = {0};
+ int rc;
+
+ /* Setup */
+ memset(ctx, 0, sizeof(mbox_context));
+
+ mbox_vlog = &mbox_log_console;
+ verbosity = (verbose)2;
+
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+ init_vpnor_from_paths(ctx);
+
+ /* Test */
+ rc = write_flash(ctx, 0x1000, src, sizeof(src));
+
+ /* Verify we can't write to RO partitions */
+ assert(rc != 0);
+
+ destroy_vpnor(ctx);
+
+ return 0;
+}
diff --git a/vpnor/test/write_rw.cpp b/vpnor/test/write_rw.cpp
new file mode 100644
index 0000000..1ee5c6c
--- /dev/null
+++ b/vpnor/test/write_rw.cpp
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+
+#include <assert.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "mbox.h"
+#include "mboxd_flash.h"
+
+#include "vpnor/test/tmpd.hpp"
+
+static constexpr auto BLOCK_SIZE = 0x1000;
+
+const std::string toc[] = {
+ "partition01=TEST1,00001000,00002000,80,ECC,READWRITE",
+};
+
+int main(void)
+{
+ namespace fs = std::experimental::filesystem;
+ namespace test = openpower::virtual_pnor::test;
+
+ struct mbox_context _ctx, *ctx = &_ctx;
+ uint8_t src[8] = {0};
+ void *map;
+ int rc;
+ int fd;
+
+ /* Setup */
+ memset(ctx, 0, sizeof(mbox_context));
+
+ mbox_vlog = &mbox_log_console;
+ verbosity = (verbose)2;
+
+ test::VpnorRoot root(ctx, toc, BLOCK_SIZE);
+ /* write_flash() doesn't copy the file for us */
+ assert(fs::copy_file(root.ro() / "TEST1", root.rw() / "TEST1"));
+ init_vpnor_from_paths(ctx);
+
+ /* Test */
+ memset(src, 0xbb, sizeof(src));
+ rc = write_flash(ctx, 0x1000, src, sizeof(src));
+ assert(rc == 0);
+ fd = open((root.rw() / "TEST1").c_str(), O_RDONLY);
+ map = mmap(NULL, sizeof(src), PROT_READ, MAP_PRIVATE, fd, 0);
+ assert(map != MAP_FAILED);
+ rc = memcmp(src, map, sizeof(src));
+ assert(rc == 0);
+
+ /* Ensure single byte writes function */
+ memset(src, 0xcc, sizeof(src));
+ rc = write_flash(ctx, 0x1000, src, sizeof(src));
+ assert(rc == 0);
+ rc = memcmp(src, map, sizeof(src));
+ assert(rc == 0);
+
+ src[0] = 0xff;
+ rc = write_flash(ctx, 0x1000, src, 1);
+ assert(rc == 0);
+ rc = memcmp(src, map, sizeof(src));
+ assert(rc == 0);
+
+ src[1] = 0xff;
+ rc = write_flash(ctx, 0x1000 + 1, &src[1], 1);
+ assert(rc == 0);
+ rc = memcmp(src, map, sizeof(src));
+ assert(rc == 0);
+
+ src[2] = 0xff;
+ rc = write_flash(ctx, 0x1000 + 2, &src[2], 1);
+ assert(rc == 0);
+ rc = memcmp(src, map, sizeof(src));
+ assert(rc == 0);
+
+ /* Writes past the end of the partition should fail */
+ rc = write_flash(ctx, 0x1000 + 0xff9, src, sizeof(src));
+ assert(rc < 0);
+
+ /* Check that RW file is unmodified after the bad write */
+ fd = open((root.rw() / "TEST1").c_str(), O_RDONLY);
+ map = mmap(NULL, sizeof(src), PROT_READ, MAP_SHARED, fd, 0);
+ assert(map != MAP_FAILED);
+ rc = memcmp(src, map, sizeof(src));
+ assert(rc == 0);
+
+ munmap(map, sizeof(src));
+ close(fd);
+
+ destroy_vpnor(ctx);
+
+ return 0;
+}
OpenPOWER on IntegriCloud