vpnor: test: Add force_readonly_toc

This ensures that the ToC presented to the host indicates that it is not
writable. The virtual PNOR implementation has never properly honoured
writes to the ToC, so lets at least tell the host.

As the code has not yet been fixed to implement the desired behaviour,
add the test to XFAIL_TESTS.

Change-Id: Ia13a0f907f916d6dec3979b17685d54bc578a106
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
diff --git a/vpnor/test/Makefile.am.include b/vpnor/test/Makefile.am.include
index 63c6240..3b366b6 100644
--- a/vpnor/test/Makefile.am.include
+++ b/vpnor/test/Makefile.am.include
@@ -226,6 +226,13 @@
 vpnor_test_write_toc_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
 vpnor_test_write_toc_LDADD = $(VPNOR_LDADD)
 
+vpnor_test_force_readonly_toc_SOURCES = \
+	$(TEST_MOCK_SRCS) \
+	$(TEST_MBOX_VPNOR_INTEG_SRCS) \
+	%reldir%/force_readonly_toc.cpp
+vpnor_test_force_readonly_toc_LDFLAGS = $(OESDK_TESTCASE_FLAGS)
+vpnor_test_force_readonly_toc_LDADD = $(VPNOR_LDADD)
+
 if VIRTUAL_PNOR_ENABLED
 check_PROGRAMS += \
 	%reldir%/create_pnor_partition_table \
@@ -256,8 +263,10 @@
 	%reldir%/create_write_window_ro_partition \
 	%reldir%/create_write_window_rw_partition \
 	%reldir%/create_write_window_unmapped \
-	%reldir%/write_toc
+	%reldir%/write_toc \
+	%reldir%/force_readonly_toc
 
 XFAIL_TESTS += \
-	%reldir%/write_toc
+	%reldir%/write_toc \
+	%reldir%/force_readonly_toc
 endif
diff --git a/vpnor/test/force_readonly_toc.cpp b/vpnor/test/force_readonly_toc.cpp
new file mode 100644
index 0000000..a783bc7
--- /dev/null
+++ b/vpnor/test/force_readonly_toc.cpp
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2018 IBM Corp.
+#include "config.h"
+
+#include "vpnor/pnor_partition_table.hpp"
+
+#include <assert.h>
+#include <endian.h>
+#include <string.h>
+#include <sys/mman.h>
+
+extern "C" {
+#include "test/mbox.h"
+#include "test/system.h"
+#include "vpnor/pnor_partition_defs.h"
+}
+
+#include "vpnor/test/tmpd.hpp"
+
+static constexpr auto BLOCK_SIZE = 4 * 1024;
+static constexpr auto PNOR_SIZE = BLOCK_SIZE;
+static constexpr auto MEM_SIZE = BLOCK_SIZE;
+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,READWRITE",
+    "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};
+
+static const uint8_t read_toc[] = {0x04, 0x04, 0x00, 0x00, 0x01, 0x00,
+                                   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                   0x00, 0x00, 0x00, 0x00};
+
+int main()
+{
+    namespace test = openpower::virtual_pnor::test;
+    namespace vpnor = openpower::virtual_pnor;
+
+    struct pnor_partition_table* htable;
+    struct mbox_context* ctx;
+    uint32_t perms;
+    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);
+
+    assert(table.capacity() == TOC_PART_SIZE);
+
+    init_vpnor_from_paths(ctx);
+
+    rc = mbox_command_dispatch(ctx, get_info, sizeof(get_info));
+    assert(rc == MBOX_R_SUCCESS);
+
+    rc = mbox_command_dispatch(ctx, read_toc, sizeof(read_toc));
+    assert(rc == MBOX_R_SUCCESS);
+
+    htable = reinterpret_cast<struct pnor_partition_table*>(ctx->mem);
+    perms = be32toh(htable->partitions[0].data.user.data[1]);
+    assert(perms & PARTITION_READONLY);
+
+    htable = reinterpret_cast<struct pnor_partition_table*>(ctx->mem);
+    perms = be32toh(htable->partitions[1].data.user.data[1]);
+    assert(!(perms & PARTITION_READONLY));
+
+    return 0;
+}