summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/xip
diff options
context:
space:
mode:
authorShakeeb <shakeebbk@in.ibm.com>2016-09-01 06:24:44 -0500
committerAMIT J. TENDOLKAR <amit.tendolkar@in.ibm.com>2016-09-01 07:48:28 -0400
commit5e83bcb5cf9d400739cfb2beaab1a3173e8cafb2 (patch)
treeb3d6cd12b5eb0c92404ae5ac0352bb360b38fa95 /src/import/chips/p9/xip
parent1008ef70a71fcfdec398ff30923d5025991c85f4 (diff)
downloadtalos-sbe-5e83bcb5cf9d400739cfb2beaab1a3173e8cafb2.tar.gz
talos-sbe-5e83bcb5cf9d400739cfb2beaab1a3173e8cafb2.zip
SBE move import`
Change-Id: I726951318cdb19fd445af2f7910e0d6872eff18c Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/29086 Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Reviewed-by: Sachin Gupta <sgupta2m@in.ibm.com> Reviewed-by: AMIT J. TENDOLKAR <amit.tendolkar@in.ibm.com>
Diffstat (limited to 'src/import/chips/p9/xip')
-rw-r--r--src/import/chips/p9/xip/Makefile85
-rw-r--r--src/import/chips/p9/xip/p9_xip_image.c3223
-rw-r--r--src/import/chips/p9/xip/p9_xip_image.h1925
-rw-r--r--src/import/chips/p9/xip/p9_xip_tool.C2594
4 files changed, 7827 insertions, 0 deletions
diff --git a/src/import/chips/p9/xip/Makefile b/src/import/chips/p9/xip/Makefile
new file mode 100644
index 00000000..b97ffc15
--- /dev/null
+++ b/src/import/chips/p9/xip/Makefile
@@ -0,0 +1,85 @@
+# IBM_PROLOG_BEGIN_TAG
+# This is an automatically generated prolog.
+#
+# $Source: import/chips/p9/xip/Makefile $
+#
+# OpenPOWER sbe Project
+#
+# Contributors Listed Below - COPYRIGHT 2015,2016
+# [+] International Business Machines Corp.
+#
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+# IBM_PROLOG_END_TAG
+
+############################################################################
+# Makefile for P9-XIP image code and tools; works on X86 Linux hosts.
+# Make targets:
+# all : Builds P9-XIP code and tools in $(OBJ_DIR)/
+# clean : Removes the $(OBJ_DIR)/ directory
+# BINDIR can be passed in to determine the ouput directory
+############################################################################
+
+# Locations of required headers.
+INCLUDES += -I.
+INCLUDES += -I../../../hwpf/fapi2/include/plat # ekb: define path variable covering ekb and ppe
+INCLUDES += -I../../../../hwpf/include/plat/ # ppe: define path variable covering ekb and ppe
+
+XIP_FLAGS += -DDEBUG_P9_XIP_IMAGE=1
+XIP_FLAGS += -DFAPI2_NO_FFDC
+
+CXX_FLAGS += -std=c++11
+
+ifdef BINDIR
+OBJ_DIR = $(BINDIR)
+else
+OBJ_DIR = bin
+endif
+
+# Under Linux the scheme is to use a common compiler to create procedures.
+# However, the common compiler can be VERY slow, so if the system compiler is
+# also 4.1.2 we're using that one instead. Also, the Linux FAPI libraries we
+# link with are 32-bit only so we need to force 32-bit mode.
+
+CXX = g++
+
+CXX_RELEASE = 4.8.2
+CXX_VERSION = $(shell $(CXX) -v 2>&1 | grep "$(CXX_RELEASE)")
+ifeq ($(CXX_VERSION),)
+$(error wrong compiler version. Use $(CXX_RELEASE) compiler. Try: "scl enable devtoolset-2 bash")
+endif
+
+XIP_UTILS = p9_xip_tool
+
+# Utility targets
+XIP_EXECUTABLES = $(patsubst %,$(OBJ_DIR)/%,$(XIP_UTILS))
+
+.PHONY : all clean
+
+all: $(OBJ_DIR) $(XIP_EXECUTABLES)
+
+$(OBJ_DIR):
+ mkdir -p $(OBJ_DIR)
+
+$(OBJ_DIR)/%.o: %.c
+ $(CXX) $(CXX_FLAGS) $(INCLUDES) $(XIP_FLAGS) -c -o $@ $<
+
+$(OBJ_DIR)/%.o: %.C
+ $(CXX) $(CXX_FLAGS) $(INCLUDES) $(XIP_FLAGS) -c -o $@ $<
+
+$(OBJ_DIR)/p9_xip_tool: $(OBJ_DIR)/p9_xip_image.o $(OBJ_DIR)/p9_xip_tool.o
+ $(CXX) -o $@ $^
+
+clean:
+ rm -rf $(OBJ_DIR)
diff --git a/src/import/chips/p9/xip/p9_xip_image.c b/src/import/chips/p9/xip/p9_xip_image.c
new file mode 100644
index 00000000..0f9ce1f7
--- /dev/null
+++ b/src/import/chips/p9/xip/p9_xip_image.c
@@ -0,0 +1,3223 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: import/chips/p9/xip/p9_xip_image.c $ */
+/* */
+/* OpenPOWER sbe Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015,2016 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+/// \file p9_xip_image.c
+/// \brief APIs for validating, normalizing, searching and manipulating
+/// P9-XIP images.
+///
+/// The background, APIs and implementation details are documented in the
+/// document "P9-XIP Binary format" currently available at this link:
+///
+/// - https://mcdoc.boeblingen.de.ibm.com/out/out.ViewDocument.php?documentid=2678
+///
+/// \bug The p9_xip_validate() API should be carefully reviewed to ensure
+/// that validating even a corrupt image can not lead to a segfault, i.e., to
+/// ensure that no memory outside of the putative bounds of the image is ever
+/// referenced during validation.
+
+#ifndef PLIC_MODULE
+ #include <stddef.h>
+ #include <stdint.h>
+ #include <stdlib.h>
+ #include <string.h>
+#endif // PLIC_MODULE
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <endian.h>
+#include "p9_xip_image.h"
+
+////////////////////////////////////////////////////////////////////////////
+// Local Functions
+////////////////////////////////////////////////////////////////////////////
+
+#ifdef DEBUG_P9_XIP_IMAGE
+
+// Debugging support, normally disabled. All of the formatted I/O you see in
+// the code is effectively under this switch.
+
+#ifdef __FAPI
+
+ #include "fapi.H"
+ #define fprintf(stream, ...) FAPI_ERR(__VA_ARGS__)
+ #define printf(...) FAPI_INF(__VA_ARGS__)
+ #define TRACE_NEWLINE ""
+
+#else // __FAPI
+
+ #include <stdio.h>
+ #define TRACE_NEWLINE "\n"
+
+#endif // __FAPI
+
+// Portable formatting of uint64_t. The ISO C99 standard requires
+// __STDC_FORMAT_MACROS to be defined in order for PRIx64 etc. to be defined.
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#define F0x016llx "0x%016" PRIx64
+#define F0x012llx "0x%012" PRIx64
+
+XIP_STATIC P9_XIP_ERROR_STRINGS(p9_xip_error_strings);
+
+#define TRACE_ERROR(x) \
+ ({ \
+ fprintf(stderr, "%s:%d : Returning error code %d : %s" TRACE_NEWLINE, \
+ __FILE__, __LINE__, (x), \
+ P9_XIP_ERROR_STRING(p9_xip_error_strings, (x))); \
+ (x); \
+ })
+
+#define TRACE_ERRORX(x, ...) \
+ ({ \
+ TRACE_ERROR(x); \
+ fprintf(stderr, ##__VA_ARGS__); \
+ (x); \
+ })
+
+// Uncomment these if required for debugging, otherwise we get warnings from
+// GCC as they are not otherwise used.
+
+#if 0
+
+XIP_STATIC P9_XIP_TYPE_STRINGS(type_strings);
+
+XIP_STATIC void
+dumpToc(int index, P9XipToc* toc)
+{
+ printf("TOC entry %d @ %p\n"
+ " iv_id = 0x%08x\n"
+ " iv_data = 0x%08x\n"
+ " iv_type = %s\n"
+ " iv_section = 0x%02x\n"
+ " iv_elements = %d\n",
+ index, toc,
+ htobe32(toc->iv_id),
+ htobe32(toc->iv_data),
+ P9_XIP_TYPE_STRING(type_strings, toc->iv_type),
+ toc->iv_section,
+ toc->iv_elements);
+}
+
+#endif
+
+#if 0
+
+XIP_STATIC void
+dumpItem(P9XipItem* item)
+{
+ printf("P9XipItem @ %p\n"
+ " iv_toc = %p\n"
+ " iv_address = " F0x016llx "\n"
+ " iv_imageData = %p\n"
+ " iv_id = %s\n"
+ " iv_type = %s\n"
+ " iv_elements = %d\n",
+ item,
+ item->iv_toc,
+ item->iv_address,
+ item->iv_imageData,
+ item->iv_id,
+ P9_XIP_TYPE_STRING(type_strings, item->iv_type),
+ item->iv_elements);
+ dumpToc(-1, item->iv_toc);
+}
+
+#endif /* 0 */
+
+XIP_STATIC void
+dumpSectionTable(const void* i_image)
+{
+ int i, rc;
+ P9XipSection section;
+
+ printf("Section table dump of image @ %p\n"
+ " Entry Offset Size\n"
+ "-------------------------------\n",
+ i_image);
+
+ for (i = 0; i < P9_XIP_SECTIONS; i++)
+ {
+ rc = p9_xip_get_section(i_image, i, &section);
+
+ if (rc)
+ {
+ printf(">>> dumpSectionTable got error at entry %d : %s\n",
+ i, P9_XIP_ERROR_STRING(p9_xip_error_strings, rc));
+ break;
+ }
+
+ printf("%7d 0x%08x 0x%08x\n",
+ i, section.iv_offset, section.iv_size);
+ }
+}
+
+#else
+
+#define TRACE_ERROR(x) (x)
+#define TRACE_ERRORX(x, ...) (x)
+#define dumpToc(...)
+#define dumpItem(...)
+#define dumpSectionTable(...)
+
+#endif
+
+
+XIP_STATIC uint64_t
+xipLinkAddress(const void* i_image)
+{
+ return htobe64(((P9XipHeader*)i_image)->iv_linkAddress);
+}
+
+
+/// What is the image size?
+
+XIP_STATIC uint32_t
+xipImageSize(const void* i_image)
+{
+ return htobe32(((P9XipHeader*)i_image)->iv_imageSize);
+}
+
+
+/// Set the image size
+
+XIP_STATIC void
+xipSetImageSize(void* io_image, const size_t i_size)
+{
+ ((P9XipHeader*)io_image)->iv_imageSize = htobe32(i_size);
+}
+
+
+/// Re-establish the required final alignment
+
+XIP_STATIC void
+xipFinalAlignment(void* io_image)
+{
+ uint32_t size;
+
+ size = xipImageSize(io_image);
+
+ if ((size % P9_XIP_FINAL_ALIGNMENT) != 0)
+ {
+ xipSetImageSize(io_image,
+ size + (P9_XIP_FINAL_ALIGNMENT -
+ (size % P9_XIP_FINAL_ALIGNMENT)));
+ }
+}
+
+
+/// Compute a host address from an image address and offset
+
+XIP_STATIC void*
+xipHostAddressFromOffset(const void* i_image, const uint32_t offset)
+{
+ return (void*)((unsigned long)i_image + offset);
+}
+
+
+/// Convert a IMAGE address to a host address
+
+XIP_STATIC void*
+xipImage2Host(const void* i_image, const uint64_t i_imageAddress)
+{
+ return xipHostAddressFromOffset(i_image,
+ i_imageAddress - xipLinkAddress(i_image));
+}
+
+
+XIP_STATIC int
+xipValidateImageAddress(const void* i_image,
+ const uint64_t i_imageAddress,
+ const uint32_t size)
+{
+ int rc;
+
+ if ((i_imageAddress < xipLinkAddress(i_image)) ||
+ (i_imageAddress > (xipLinkAddress(i_image) +
+ xipImageSize(i_image) -
+ size)))
+ {
+ rc = TRACE_ERRORX(P9_XIP_INVALID_ARGUMENT,
+ "The IMAGE address " F0x012llx
+ " is outside the bounds "
+ "of the image ("
+ F0x012llx ":" F0x012llx
+ ") for %u-byte access.\n",
+ i_imageAddress,
+ xipLinkAddress(i_image),
+ xipLinkAddress(i_image) + xipImageSize(i_image) - 1,
+ size);
+ }
+ else
+ {
+ rc = 0;
+ }
+
+ return rc;
+}
+
+
+/// Get the magic number from the image
+
+XIP_STATIC uint64_t
+xipMagic(const void* i_image)
+{
+ return htobe64(((P9XipHeader*)i_image)->iv_magic);
+}
+
+
+/// Get the header version from the image
+
+XIP_STATIC uint8_t
+xipHeaderVersion(const void* i_image)
+{
+ return ((P9XipHeader*)i_image)->iv_headerVersion;
+}
+
+
+/// Has the image been normalized?
+
+XIP_STATIC uint8_t
+xipNormalized(const void* i_image)
+{
+ return ((P9XipHeader*)i_image)->iv_normalized;
+}
+
+
+/// Has the image TOC been sorted?
+
+XIP_STATIC uint8_t
+xipSorted(const void* i_image)
+{
+ return ((P9XipHeader*)i_image)->iv_tocSorted;
+}
+
+
+/// A quick check that the image exists, has the correct magic and header
+/// version, and optionally is normalized.
+
+XIP_STATIC int
+xipQuickCheck(const void* i_image, const int i_normalizationRequired)
+{
+ int rc;
+
+ do
+ {
+ rc = 0;
+
+ if (i_image == 0)
+ {
+ rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR,
+ "Image pointer is NULL (0)\n");
+ break;
+ }
+
+ if ((xipMagic(i_image) >> 32) != P9_XIP_MAGIC)
+ {
+ rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR,
+ "Magic number mismatch; Found "
+ "" F0x016llx ", expected 0x%08x........\n",
+ xipMagic(i_image), P9_XIP_MAGIC);
+ break;
+ }
+
+ if ((xipHeaderVersion(i_image)) != P9_XIP_HEADER_VERSION)
+ {
+ rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR,
+ "Header version mismatch; Expecting %d, "
+ "found %d\n",
+ P9_XIP_HEADER_VERSION,
+ xipHeaderVersion(i_image));
+ break;
+ }
+
+ if (i_normalizationRequired && !xipNormalized(i_image))
+ {
+ rc = TRACE_ERRORX(P9_XIP_NOT_NORMALIZED,
+ "Image not normalized\n");
+ break;
+ }
+ }
+ while(0);
+
+ return rc;
+}
+
+
+/// Convert a 32-bit relocatable offset to a full IMAGE 48-bit address
+
+XIP_STATIC uint64_t
+xipFullAddress(const void* i_image, uint32_t offset)
+{
+ return (xipLinkAddress(i_image) & 0x0000ffff00000000ull) + offset;
+}
+
+
+/// Translate a section table entry
+
+XIP_STATIC void
+xipTranslateSection(P9XipSection* o_dest, const P9XipSection* i_src)
+{
+#ifndef _BIG_ENDIAN
+
+#if P9_XIP_HEADER_VERSION != 9
+#error This code assumes the P9-XIP header version 9 layout
+#endif
+
+ o_dest->iv_offset = htobe32(i_src->iv_offset);
+ o_dest->iv_size = htobe32(i_src->iv_size);
+ o_dest->iv_alignment = i_src->iv_alignment;
+ o_dest->iv_reserved8[0] = 0;
+ o_dest->iv_reserved8[1] = 0;
+ o_dest->iv_reserved8[2] = 0;
+#else
+
+ if (o_dest != i_src)
+ {
+ *o_dest = *i_src;
+ }
+
+#endif /* _BIG_ENDIAN */
+}
+
+
+/// Translate a TOC entry
+
+XIP_STATIC void
+xipTranslateToc(P9XipToc* o_dest, P9XipToc* i_src)
+{
+#ifndef _BIG_ENDIAN
+
+#if P9_XIP_HEADER_VERSION != 9
+#error This code assumes the P9-XIP header version 9 layout
+#endif
+
+ o_dest->iv_id = htobe32(i_src->iv_id);
+ o_dest->iv_data = htobe32(i_src->iv_data);
+ o_dest->iv_type = i_src->iv_type;
+ o_dest->iv_section = i_src->iv_section;
+ o_dest->iv_elements = i_src->iv_elements;
+ o_dest->iv_pad = 0;
+#else
+
+ if (o_dest != i_src)
+ {
+ *o_dest = *i_src;
+ }
+
+#endif /* _BIG_ENDIAN */
+}
+
+
+/// Find the final (highest-address) section of the image
+
+XIP_STATIC int
+xipFinalSection(const void* i_image, int* o_sectionId)
+{
+ int i, rc, found;
+ uint32_t offset;
+ P9XipHeader hostHeader;
+
+ p9_xip_translate_header(&hostHeader, (P9XipHeader*)i_image);
+
+ found = 0;
+ offset = 0;
+ *o_sectionId = 0; /* Make GCC -O3 happy */
+
+ for (i = 0; i < P9_XIP_SECTIONS; i++)
+ {
+ if ((hostHeader.iv_section[i].iv_size != 0) &&
+ (hostHeader.iv_section[i].iv_offset >= offset))
+ {
+ *o_sectionId = i;
+ offset = hostHeader.iv_section[i].iv_offset;
+ found = 1;
+ }
+ }
+
+ if (!found)
+ {
+ rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, "The image is empty\n");
+ }
+ else
+ {
+ rc = 0;
+ }
+
+ return rc;
+}
+
+
+/// Return a pointer to an image-format section table entry
+
+XIP_STATIC int
+xipGetSectionPointer(const void* i_image,
+ const int i_sectionId,
+ P9XipSection** o_imageSection)
+{
+ int rc;
+
+ if ((i_sectionId < 0) || (i_sectionId >= P9_XIP_SECTIONS))
+ {
+ rc = TRACE_ERROR(P9_XIP_INVALID_ARGUMENT);
+ }
+ else
+ {
+ *o_imageSection =
+ &(((P9XipHeader*)i_image)->iv_section[i_sectionId]);
+ rc = 0;
+ }
+
+ return rc;
+}
+
+
+/// Restore a section table entry from host format to image format.
+
+XIP_STATIC int
+xipPutSection(const void* i_image,
+ const int i_sectionId,
+ P9XipSection* i_hostSection)
+{
+ int rc;
+ P9XipSection* imageSection;
+
+ rc = xipGetSectionPointer(i_image, i_sectionId, &imageSection);
+
+ if (!rc)
+ {
+ xipTranslateSection(imageSection, i_hostSection);
+ }
+
+ return rc;
+}
+
+
+/// Set the offset of a section
+
+XIP_STATIC int
+xipSetSectionOffset(void* io_image, const int i_section,
+ const uint32_t i_offset)
+{
+ P9XipSection* section;
+ int rc;
+
+ rc = xipGetSectionPointer(io_image, i_section, &section);
+
+ if (!rc)
+ {
+ section->iv_offset = htobe32(i_offset);
+ }
+
+ return rc;
+}
+
+
+/// Set the size of a section
+
+XIP_STATIC int
+xipSetSectionSize(void* io_image, const int i_section, const uint32_t i_size)
+{
+ P9XipSection* section;
+ int rc;
+
+ rc = xipGetSectionPointer(io_image, i_section, &section);
+
+ if (!rc)
+ {
+ section->iv_size = htobe32(i_size);
+ }
+
+ return rc;
+}
+
+
+/// Translate a IMAGE address in the image to a section and offset
+
+// We first check to be sure that the IMAGE address is contained in the image,
+// using the full 48-bit form. Then we scan the section table to see which
+// section contains the address - if none then the image is corrupted. We can
+// (must) use the 32-bit offset form of the address here.
+
+XIP_STATIC int
+xipImage2Section(const void* i_image,
+ const uint64_t i_imageAddress,
+ int* o_section,
+ uint32_t* o_offset)
+{
+ int rc, sectionId;
+ P9XipSection section;
+ uint32_t addressOffset;
+
+ do
+ {
+ rc = 0;
+
+ if ((i_imageAddress < xipLinkAddress(i_image)) ||
+ (i_imageAddress >
+ (xipLinkAddress(i_image) + xipImageSize(i_image))))
+ {
+ rc = TRACE_ERRORX(P9_XIP_INVALID_ARGUMENT,
+ "image2section: The i_imageAddress argument "
+ "(" F0x016llx ")\nis outside the bounds of the "
+ "image (" F0x016llx ":" F0x016llx ")\n",
+ i_imageAddress,
+ xipLinkAddress(i_image),
+ xipLinkAddress(i_image) + xipImageSize(i_image));
+ break;
+ }
+
+ addressOffset = (i_imageAddress - xipLinkAddress(i_image)) & 0xffffffff;
+
+ for (sectionId = 0; sectionId < P9_XIP_SECTIONS; sectionId++)
+ {
+ rc = p9_xip_get_section(i_image, sectionId, &section);
+
+ if (rc)
+ {
+ rc = TRACE_ERROR(P9_XIP_BUG); /* Can't happen */
+ break;
+ }
+
+ if ((section.iv_size != 0) &&
+ (addressOffset >= section.iv_offset) &&
+ (addressOffset < (section.iv_offset + section.iv_size)))
+ {
+ break;
+ }
+ }
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (sectionId == P9_XIP_SECTIONS)
+ {
+ rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR,
+ "Error processing IMAGE address " F0x016llx ". "
+ "The address is not mapped in any section.\n"
+ "A section table dump appears below\n",
+ i_imageAddress);
+ dumpSectionTable(i_image);
+ break;
+ }
+
+ *o_section = sectionId;
+ *o_offset = addressOffset - section.iv_offset;
+
+ }
+ while(0);
+
+ return rc;
+}
+
+
+// Delete the last, i.e., final, section of the image.
+
+XIP_STATIC int
+xipDeleteLastSection(void* io_image,
+ const int i_sectionId)
+{
+ int rc, final;
+ P9XipSection section;
+
+ do
+ {
+
+ xipSetSectionOffset(io_image, i_sectionId, 0);
+ xipSetSectionSize(io_image, i_sectionId, 0);
+
+
+ // For cleanliness we also remove any alignment padding that had been
+ // appended between the now-last section and the deleted section, then
+ // re-establish the final alignment. The assumption is that all images
+ // always have the correct final alignment, so there is no way this
+ // could overflow a designated buffer space since the image size is
+ // the same or has been reduced.
+
+ rc = xipFinalSection(io_image, &final);
+
+ if (rc)
+ {
+ break;
+ }
+
+ rc = p9_xip_get_section(io_image, final, &section);
+
+ if (rc)
+ {
+ break;
+ }
+
+ xipSetImageSize(io_image, section.iv_offset + section.iv_size);
+ xipFinalAlignment(io_image);
+
+ }
+ while (0);
+
+ return rc;
+}
+
+
+/// Get the information required to search the TOC.
+///
+/// All return values are optional.
+
+int
+p9_xip_get_toc(void* i_image,
+ P9XipToc** o_toc,
+ size_t* o_entries,
+ int* o_sorted,
+ char** o_strings)
+{
+ int rc;
+ P9XipSection tocSection, stringsSection;
+
+ do
+ {
+ rc = p9_xip_get_section(i_image, P9_XIP_SECTION_TOC, &tocSection);
+
+ if (rc)
+ {
+ break;
+ }
+
+ rc = p9_xip_get_section(i_image, P9_XIP_SECTION_STRINGS,
+ &stringsSection);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (o_toc)
+ {
+ *o_toc = (P9XipToc*)((uint8_t*)i_image + tocSection.iv_offset);
+ }
+
+ if (o_entries)
+ {
+ *o_entries = tocSection.iv_size / sizeof(P9XipToc);
+ }
+
+ if (o_sorted)
+ {
+ *o_sorted = xipSorted(i_image);
+ }
+
+ if (o_strings)
+ {
+ *o_strings = (char*)i_image + stringsSection.iv_offset;
+ }
+ }
+ while (0);
+
+ return rc;
+}
+
+
+/// Compare two normalized TOC entries for sorting.
+
+XIP_STATIC int
+xipCompareToc(const P9XipToc* i_a, const P9XipToc* i_b,
+ const char* i_strings)
+{
+ return strcmp(i_strings + htobe32(i_a->iv_id),
+ i_strings + htobe32(i_b->iv_id));
+}
+
+
+/// Iterative quicksort of the TOC
+
+// Note: The stack requirement is limited to 256 bytes + minor local storage.
+
+XIP_STATIC void
+xipQuickSort(P9XipToc* io_toc, int i_left, int i_right,
+ const char* i_strings)
+{
+ int i, j, left, right, sp;
+ P9XipToc pivot, temp;
+ uint32_t stack[64];
+
+ sp = 0;
+ stack[sp++] = i_left;
+ stack[sp++] = i_right;
+
+ while (sp)
+ {
+
+ right = stack[--sp];
+ left = stack[--sp];
+
+ i = left;
+ j = right;
+
+ pivot = io_toc[(i + j) / 2];
+
+ while (i <= j)
+ {
+ while (xipCompareToc(&(io_toc[i]), &pivot, i_strings) < 0)
+ {
+ i++;
+ }
+
+ while (xipCompareToc(&(io_toc[j]), &pivot, i_strings) > 0)
+ {
+ j--;
+ }
+
+ if (i <= j)
+ {
+ temp = io_toc[i];
+ io_toc[i] = io_toc[j];
+ io_toc[j] = temp;
+ i++;
+ j--;
+ }
+ }
+
+ if (left < j)
+ {
+ stack[sp++] = left;
+ stack[sp++] = j;
+ }
+
+ if (i < right)
+ {
+ stack[sp++] = i;
+ stack[sp++] = right;
+ }
+ }
+}
+
+
+/// TOC linear search
+
+XIP_STATIC int
+xipLinearSearch(void* i_image, const char* i_id, P9XipToc** o_entry)
+{
+ int rc;
+ P9XipToc* imageToc, hostToc;
+ size_t entries;
+ char* strings;
+
+ *o_entry = 0;
+ rc = p9_xip_get_toc(i_image, &imageToc, &entries, 0, &strings);
+
+ if (!rc)
+ {
+ for (; entries; entries--, imageToc++)
+ {
+ xipTranslateToc(&hostToc, imageToc);
+
+ if (strcmp(i_id, strings + hostToc.iv_id) == 0)
+ {
+ break;
+ }
+ }
+
+ if (entries)
+ {
+ *o_entry = imageToc;
+ rc = 0;
+ }
+ else
+ {
+ *o_entry = 0;
+ rc = TRACE_ERROR(P9_XIP_ITEM_NOT_FOUND);
+ }
+ }
+
+ return rc;
+}
+
+
+/// A classic binary search of a (presumed) sorted array
+
+XIP_STATIC int
+xipBinarySearch(void* i_image, const char* i_id, P9XipToc** o_entry)
+{
+ int rc;
+ P9XipToc* imageToc;
+ size_t entries;
+ char* strings;
+ int sorted, left, right, next, sort;
+
+ do
+ {
+ *o_entry = 0;
+
+ rc = p9_xip_get_toc(i_image, &imageToc, &entries, &sorted, &strings);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (!sorted)
+ {
+ rc = TRACE_ERROR(P9_XIP_BUG);
+ break;
+ }
+
+ left = 0;
+ right = entries - 1;
+
+ while (left <= right)
+ {
+ next = (left + right) / 2;
+ sort = strcmp(i_id, strings + htobe32(imageToc[next].iv_id));
+
+ if (sort == 0)
+ {
+ *o_entry = &(imageToc[next]);
+ break;
+ }
+ else if (sort < 0)
+ {
+ right = next - 1;
+ }
+ else
+ {
+ left = next + 1;
+ }
+ }
+
+ if (*o_entry == 0)
+ {
+ rc = TRACE_ERROR(P9_XIP_ITEM_NOT_FOUND);
+ break;
+ }
+ }
+ while (0);
+
+ return rc;
+}
+
+
+/// Validate a TOC entry as a mapping function
+///
+/// The TOC is validated by searching for the entry, which will uncover
+/// duplicate entries or problems with sorting/searching.
+
+XIP_STATIC int
+xipValidateTocEntry(void* io_image, const P9XipItem* i_item, void* io_arg)
+{
+ int rc;
+ P9XipItem found;
+
+ do
+ {
+ rc = p9_xip_find(io_image, i_item->iv_id, &found);
+
+ if (rc)
+ {
+ rc = TRACE_ERRORX(rc, "TOC entry for %s not found\n",
+ i_item->iv_id);
+ }
+ else if (found.iv_toc != i_item->iv_toc)
+ {
+ rc = TRACE_ERRORX(P9_XIP_TOC_ERROR,
+ "Duplicate TOC entry for '%s'\n", i_item->iv_id);
+ }
+
+ break;
+ }
+ while (0);
+
+ return rc;
+}
+
+
+// This is the FNV-1a hash, used for hashing symbol names in the .fixed
+// section into 32-bit hashes for the mini-TOC.
+
+// According to the authors:
+
+// "FNV hash algorithms and source code have been released into the public
+// domain. The authors of the FNV algorithmm look deliberate steps to disclose
+// the algorhtm (sic) in a public forum soon after it was invented. More than
+// a year passed after this public disclosure and the authors deliberatly took
+// no steps to patent the FNV algorithm. Therefore it is safe to say that the
+// FNV authors have no patent claims on the FNV algorithm as published."
+
+#define FNV_OFFSET_BASIS 2166136261u
+#define FNV_PRIME32 16777619u
+
+uint32_t
+xipHash32(const char* s)
+{
+ uint32_t hash;
+
+ hash = FNV_OFFSET_BASIS;
+
+ while (*s)
+ {
+ hash ^= *s++;
+ hash *= FNV_PRIME32;
+ }
+
+ return hash;
+}
+
+
+// Normalize a TOC entry
+
+// Normalize the TOC entry by converting relocatable pointers into 32-bit
+// offsets from the beginning of the section containing the data. All
+// addresses in the TOC are actually 32-bit offsets in the address space named
+// in bits 16:31 of the link address of the image.
+
+XIP_STATIC int
+xipNormalizeToc(void* io_image, P9XipToc* io_imageToc,
+ P9XipHashedToc** io_fixedTocEntry,
+ size_t* io_fixedEntriesRemaining)
+{
+ P9XipToc hostToc;
+ int idSection, dataSection;
+ uint32_t idOffset, dataOffset;
+ char* hostString;
+ int rc;
+
+ do
+ {
+
+ // Translate the TOC entry to host format. Then locate the
+ // sections/offsets of the Id string (which must be in .strings) and
+ // the data.
+
+ xipTranslateToc(&hostToc, io_imageToc);
+
+ hostString =
+ (char*)xipImage2Host(io_image,
+ xipFullAddress(io_image, hostToc.iv_id));
+
+ rc = xipImage2Section(io_image,
+ xipFullAddress(io_image, hostToc.iv_id),
+ &idSection,
+ &idOffset);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (idSection != P9_XIP_SECTION_STRINGS)
+ {
+ rc = TRACE_ERROR(P9_XIP_IMAGE_ERROR);
+ break;
+ }
+
+ rc = xipImage2Section(io_image,
+ xipFullAddress(io_image, hostToc.iv_data),
+ &dataSection,
+ &dataOffset);
+
+ if (rc)
+ {
+ break;
+ }
+
+ // Now replace the Id and data pointers with their offsets, and update
+ // the data section in the TOC entry.
+
+ hostToc.iv_id = idOffset;
+ hostToc.iv_data = dataOffset;
+ hostToc.iv_section = dataSection;
+
+ // If this TOC entry is from .fixed, create a new record in .fixed_toc
+
+ if (hostToc.iv_section == P9_XIP_SECTION_FIXED)
+ {
+
+ if (*io_fixedEntriesRemaining == 0)
+ {
+ rc = TRACE_ERRORX(P9_XIP_TOC_ERROR,
+ "Too many TOC entries for .fixed\n");
+ break;
+ }
+
+ if (hostToc.iv_data != (uint16_t)hostToc.iv_data)
+ {
+ rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR,
+ "The .fixed section is too big to index\n");
+ break;
+ }
+
+ (*io_fixedTocEntry)->iv_hash = htobe32(xipHash32(hostString));
+ (*io_fixedTocEntry)->iv_offset = htobe16(hostToc.iv_data);
+ (*io_fixedTocEntry)->iv_type = hostToc.iv_type;
+ (*io_fixedTocEntry)->iv_elements = hostToc.iv_elements;
+
+ (*io_fixedTocEntry)++;
+ (*io_fixedEntriesRemaining)--;
+ }
+
+ // Finally update the TOC entry
+
+ xipTranslateToc(io_imageToc, &hostToc);
+
+ }
+ while (0);
+
+ return rc;
+}
+
+
+// Check for hash collisions in the .fixed mini-TOC. Note that endianness is
+// not an issue here, as we're comparing for equality.
+
+XIP_STATIC int
+xipHashCollision(P9XipHashedToc* i_fixedToc, size_t i_entries)
+{
+ int rc;
+ size_t i, j;
+
+ rc = 0;
+
+ for (i = 0; i < i_entries; i++)
+ {
+ for (j = i + 1; j < i_entries; j++)
+ {
+ if (i_fixedToc[i].iv_hash == i_fixedToc[j].iv_hash)
+ {
+ rc = TRACE_ERRORX(P9_XIP_HASH_COLLISION,
+ "Hash collision at index %zd\n",
+ i);
+ break;
+ }
+ }
+
+ if (rc)
+ {
+ break;
+ }
+ }
+
+ return rc;
+}
+
+
+/// Decode a normalized image-format TOC entry into a host-format P9XipItem
+/// structure
+
+XIP_STATIC int
+xipDecodeToc(void* i_image,
+ P9XipToc* i_imageToc,
+ P9XipItem* o_item)
+{
+ int rc;
+ P9XipToc hostToc;
+ P9XipSection dataSection, stringsSection;
+
+ do
+ {
+ if (!xipNormalized(i_image))
+ {
+ rc = TRACE_ERROR(P9_XIP_NOT_NORMALIZED);
+ break;
+ }
+
+
+ // Translate the TOC entry and set the TOC pointer, data type and
+ // number of elements in the outgoing structure. The Id string is
+ // always located in the TOC_STRINGS section.
+
+ xipTranslateToc(&hostToc, i_imageToc);
+
+ o_item->iv_toc = i_imageToc;
+ o_item->iv_type = hostToc.iv_type;
+ o_item->iv_elements = hostToc.iv_elements;
+
+ p9_xip_get_section(i_image, P9_XIP_SECTION_STRINGS, &stringsSection);
+ o_item->iv_id =
+ (char*)i_image + stringsSection.iv_offset + hostToc.iv_id;
+
+
+ // The data (or text address) are addressed by relative offsets from
+ // the beginning of their section. The TOC entry may remain in the TOC
+ // even though the section has been removed from the image, so this
+ // case needs to be covered.
+
+ rc = p9_xip_get_section(i_image, hostToc.iv_section, &dataSection);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (dataSection.iv_size == 0)
+ {
+ rc = TRACE_ERROR(P9_XIP_DATA_NOT_PRESENT);
+ break;
+ }
+
+ o_item->iv_imageData =
+ (void*)((uint8_t*)i_image +
+ dataSection.iv_offset + hostToc.iv_data);
+
+ o_item->iv_address =
+ xipLinkAddress(i_image) + dataSection.iv_offset + hostToc.iv_data;
+
+ o_item->iv_partial = 0;
+
+ }
+ while (0);
+
+ return rc;
+}
+
+int
+p9_xip_decode_toc_dump(void* i_image, void* i_dump,
+ P9XipToc* i_imageToc,
+ P9XipItem* o_item)
+{
+ int rc = 0;
+ P9XipToc hostToc = {0};
+ P9XipSection stringsSection = {0};
+
+ if (!xipNormalized(i_image))
+ {
+ rc = TRACE_ERROR(P9_XIP_NOT_NORMALIZED);
+ return rc;
+ }
+
+ // Translate the TOC entry and set the TOC pointer, data type and
+ // number of elements in the outgoing structure. The Id string is
+ // always located in the TOC_STRINGS section.
+
+ xipTranslateToc(&hostToc, i_imageToc);
+
+ o_item->iv_toc = i_imageToc;
+ o_item->iv_type = hostToc.iv_type;
+ o_item->iv_elements = hostToc.iv_elements;
+
+ p9_xip_get_section(i_image, P9_XIP_SECTION_STRINGS, &stringsSection);
+ o_item->iv_id =
+ (char*)i_image + stringsSection.iv_offset + hostToc.iv_id;
+
+ //Print only the attributes present in fixed section of SEEPROM image
+ if (hostToc.iv_section == P9_XIP_SECTION_FIXED)
+ {
+ //get the attribute value from dump file
+ o_item->iv_imageData = (void*)((uint8_t*)i_dump + hostToc.iv_data);
+ o_item->iv_address = xipLinkAddress(i_image) + hostToc.iv_data;
+ o_item->iv_partial = 0;
+ }
+ else
+ {
+ o_item->iv_address = 0;
+ }
+
+ return rc;
+}
+
+/// Sort the TOC
+
+XIP_STATIC int
+xipSortToc(void* io_image)
+{
+ int rc;
+ P9XipToc* hostToc;
+ size_t entries;
+ char* strings;
+
+ do
+ {
+ rc = xipQuickCheck(io_image, 1);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (xipSorted(io_image))
+ {
+ break;
+ }
+
+ rc = p9_xip_get_toc(io_image, &hostToc, &entries, 0, &strings);
+
+ if (rc)
+ {
+ break;
+ }
+
+ xipQuickSort(hostToc, 0, entries - 1, strings);
+
+ ((P9XipHeader*)io_image)->iv_tocSorted = 1;
+
+ }
+ while (0);
+
+ return rc;
+}
+
+
+// Pad the image with 0 to a given power-of-2 alignment. The image size is
+// modified to reflect the pad, but the caller must modify the section size to
+// reflect the pad.
+
+XIP_STATIC int
+xipPadImage(void* io_image, uint32_t i_allocation,
+ uint32_t i_align, uint32_t* pad)
+{
+ int rc;
+
+ do
+ {
+ rc = 0;
+
+ if ((i_align == 0) || ((i_align & (i_align - 1)) != 0))
+ {
+ rc = TRACE_ERRORX(P9_XIP_INVALID_ARGUMENT,
+ "Alignment specification (%u) "
+ "not a power-of-2\n",
+ i_align);
+ break;
+ }
+
+ *pad = xipImageSize(io_image) % i_align;
+
+ if (*pad != 0)
+ {
+ *pad = i_align - *pad;
+
+ if ((xipImageSize(io_image) + *pad) > i_allocation)
+ {
+ rc = TRACE_ERROR(P9_XIP_WOULD_OVERFLOW);
+ break;
+ }
+
+ memset((void*)((unsigned long)io_image + xipImageSize(io_image)),
+ 0, *pad);
+ xipSetImageSize(io_image, xipImageSize(io_image) + *pad);
+ }
+ }
+ while (0);
+
+ return rc;
+}
+
+
+// Get the .fixed_toc section
+
+XIP_STATIC int
+xipGetFixedToc(void* io_image,
+ P9XipHashedToc** o_imageToc,
+ size_t* o_entries)
+{
+ int rc;
+ P9XipSection section;
+
+ rc = p9_xip_get_section(io_image, P9_XIP_SECTION_FIXED_TOC, &section);
+
+ if (!rc)
+ {
+
+ *o_imageToc =
+ (P9XipHashedToc*)((unsigned long)io_image + section.iv_offset);
+
+ *o_entries = section.iv_size / sizeof(P9XipHashedToc);
+ }
+
+ return rc;
+}
+
+
+// Search for an item in the fixed TOC, and populate a partial TOC entry if
+// requested. This table is small and unsorted so a linear search is
+// adequate. The TOC structures are also small so all byte-reversal is done
+// 'by hand' rather than with a translate-type API.
+
+XIP_STATIC int
+xipFixedFind(void* i_image, const char* i_id, P9XipItem* o_item)
+{
+ int rc;
+ P9XipHashedToc* toc;
+ size_t entries;
+ uint32_t hash;
+ P9XipSection fixedSection;
+ uint32_t offset;
+
+ do
+ {
+ rc = xipGetFixedToc(i_image, &toc, &entries);
+
+ if (rc)
+ {
+ break;
+ }
+
+ for (hash = htobe32(xipHash32(i_id)); entries != 0; entries--, toc++)
+ {
+ if (toc->iv_hash == hash)
+ {
+ break;
+ }
+ }
+
+ if (entries == 0)
+ {
+ rc = P9_XIP_ITEM_NOT_FOUND;
+ break;
+ }
+ else
+ {
+ rc = 0;
+ }
+
+ // The caller may have requested a lookup only (o_item == 0), in which
+ // case we're done. Otherwise we create a partial P9XipItem and
+ // populate the non-0 fields analogously to the xipDecodeToc()
+ // routine. The data resides in the .fixed section in this case.
+
+ if (o_item == 0)
+ {
+ break;
+ }
+
+ o_item->iv_partial = 1;
+ o_item->iv_toc = 0;
+ o_item->iv_id = 0;
+
+ o_item->iv_type = toc->iv_type;
+ o_item->iv_elements = toc->iv_elements;
+
+ rc = p9_xip_get_section(i_image, P9_XIP_SECTION_FIXED, &fixedSection);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (fixedSection.iv_size == 0)
+ {
+ rc = TRACE_ERROR(P9_XIP_DATA_NOT_PRESENT);
+ break;
+ }
+
+ offset = fixedSection.iv_offset + htobe16(toc->iv_offset);
+
+ o_item->iv_imageData = (void*)((uint8_t*)i_image + offset);
+ o_item->iv_address = xipLinkAddress(i_image) + offset;
+
+ }
+ while (0);
+
+ return rc;
+}
+
+
+// Search for an item in the special built-in TOC of header fields, and
+// populate a partial TOC entry if requested.
+//
+// This facility was added to allow header data to be searched by name even
+// when the TOC has been stripped. This API will only be used in the case of a
+// stripped TOC since the header fields are also indexed in the main TOC.
+//
+// The table is allocated on the stack in order to make this code concurrently
+// patchable in PHYP (although PHYP applications will never use this code).
+// The table is small and unsorted so a linear search is adequate, and the
+// stack requirememts are small.
+
+XIP_STATIC int
+xipHeaderFind(void* i_image, const char* i_id, P9XipItem* o_item)
+{
+ int rc;
+ unsigned i;
+ uint32_t offset;
+ P9XipSection headerSection;
+
+#define HEADER_TOC(id, field, type) \
+ {#id, offsetof(P9XipHeader, field), type}
+
+ struct HeaderToc
+ {
+
+ const char* iv_id;
+ uint16_t iv_offset;
+ uint8_t iv_type;
+
+ } toc[] =
+ {
+
+ HEADER_TOC(magic, iv_magic, P9_XIP_UINT64),
+ HEADER_TOC(link_address, iv_linkAddress, P9_XIP_UINT64),
+
+ HEADER_TOC(image_size, iv_imageSize, P9_XIP_UINT32),
+ HEADER_TOC(build_date, iv_buildDate, P9_XIP_UINT32),
+ HEADER_TOC(build_time, iv_buildTime, P9_XIP_UINT32),
+
+ HEADER_TOC(header_version, iv_headerVersion, P9_XIP_UINT8),
+ HEADER_TOC(toc_normalized, iv_normalized, P9_XIP_UINT8),
+ HEADER_TOC(toc_sorted, iv_tocSorted, P9_XIP_UINT8),
+
+ HEADER_TOC(build_user, iv_buildUser, P9_XIP_STRING),
+ HEADER_TOC(build_host, iv_buildHost, P9_XIP_STRING),
+
+ };
+
+ do
+ {
+
+ rc = P9_XIP_ITEM_NOT_FOUND;
+
+ for (i = 0; i < (sizeof(toc) / sizeof(struct HeaderToc)); i++)
+ {
+ if (strcmp(i_id, toc[i].iv_id) == 0)
+ {
+ rc = 0;
+ break;
+ }
+ }
+
+ if (rc)
+ {
+ break;
+ }
+
+ // The caller may have requested a lookup only (o_item == 0), in which
+ // case we're done. Otherwise we create a partial P9XipItem and
+ // populate the non-0 fields analogously to the xipDecodeToc()
+ // routine. The data resides in the .fixed section in this case.
+
+ if (o_item == 0)
+ {
+ break;
+ }
+
+ o_item->iv_partial = 1;
+ o_item->iv_toc = 0;
+ o_item->iv_id = 0;
+
+ o_item->iv_type = toc[i].iv_type;
+ o_item->iv_elements = 1; /* True for now... */
+
+ rc = p9_xip_get_section(i_image, P9_XIP_SECTION_HEADER,
+ &headerSection);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (headerSection.iv_size == 0)
+ {
+ rc = TRACE_ERROR(P9_XIP_DATA_NOT_PRESENT);
+ break;
+ }
+
+ offset = headerSection.iv_offset + toc[i].iv_offset;
+
+ o_item->iv_imageData = (void*)((uint8_t*)i_image + offset);
+ o_item->iv_address = xipLinkAddress(i_image) + offset;
+
+ }
+ while (0);
+
+ return rc;
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+// Published API
+////////////////////////////////////////////////////////////////////////////
+
+int
+p9_xip_validate(void* i_image, const uint32_t i_size)
+{
+ P9XipHeader hostHeader;
+ int rc = 0, i;
+ uint32_t linkAddress, imageSize, extent, offset, size;
+ uint8_t alignment;
+
+ p9_xip_translate_header(&hostHeader, (P9XipHeader*)i_image);
+
+ do
+ {
+
+ // Validate C/Assembler constraints.
+
+ if (sizeof(P9XipSection) != SIZE_OF_P9_XIP_SECTION)
+ {
+ rc = TRACE_ERRORX(P9_XIP_BUG,
+ "C/Assembler size mismatch(%ld/%d) "
+ "for P9XipSection\n",
+ sizeof(P9XipSection), SIZE_OF_P9_XIP_SECTION);
+ break;
+ }
+
+ if (sizeof(P9XipToc) != SIZE_OF_P9_XIP_TOC)
+ {
+ rc = TRACE_ERRORX(P9_XIP_BUG,
+ "C/Assembler size mismatch(%ld/%d) "
+ "for P9XipToc\n",
+ sizeof(P9XipToc), SIZE_OF_P9_XIP_TOC);
+ break;
+ }
+
+ if (sizeof(P9XipHashedToc) != SIZE_OF_P9_XIP_HASHED_TOC)
+ {
+ rc = TRACE_ERRORX(P9_XIP_BUG,
+ "C/Assembler size mismatch(%ld/%d) "
+ "for P9XipHashedToc\n",
+ sizeof(P9XipHashedToc),
+ SIZE_OF_P9_XIP_HASHED_TOC);
+ break;
+ }
+
+ // Validate the image pointer and magic number
+
+ rc = xipQuickCheck(i_image, 0);
+
+ if (rc)
+ {
+ break;
+ }
+
+ // Validate the image size
+
+ linkAddress = hostHeader.iv_linkAddress;
+ imageSize = hostHeader.iv_imageSize;
+ extent = linkAddress + imageSize;
+
+ if (imageSize < sizeof(P9XipHeader))
+ {
+ rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR,
+ "p9_xip_validate(%p, %u) : "
+ "The image size recorded in the image "
+ "(%u) is smaller than the header size.\n",
+ i_image, i_size, imageSize);
+ break;
+ }
+
+ if (imageSize != i_size)
+ {
+ rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR,
+ "p9_xip_validate(%p, %u) : "
+ "The image size recorded in the image "
+ "(%u) does not match the i_size parameter.\n",
+ i_image, i_size, imageSize);
+ break;
+ }
+
+ if (extent <= linkAddress)
+ {
+ rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR,
+ "p9_xip_validate(%p, %u) : "
+ "Given the link address (%u) and the "
+ "image size, the image wraps the address space\n",
+ i_image, i_size, linkAddress);
+ break;
+ }
+
+ if ((imageSize % P9_XIP_FINAL_ALIGNMENT) != 0)
+ {
+ rc = TRACE_ERRORX(P9_XIP_ALIGNMENT_ERROR,
+ "p9_xip_validate(%p, %u) : "
+ "The image size (%u) is not a multiple of %u\n",
+ i_image, i_size, imageSize,
+ P9_XIP_FINAL_ALIGNMENT);
+ break;
+ }
+
+ // Validate that all sections appear to be within the image
+ // bounds, and are aligned correctly.
+
+ for (i = 0; i < P9_XIP_SECTIONS; i++)
+ {
+
+ offset = hostHeader.iv_section[i].iv_offset;
+ size = hostHeader.iv_section[i].iv_size;
+ alignment = hostHeader.iv_section[i].iv_alignment;
+
+ if ((offset > imageSize) ||
+ ((offset + size) > imageSize) ||
+ ((offset + size) < offset))
+ {
+ rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR,
+ "Section %d does not appear to be within "
+ "the bounds of the image\n"
+ "offset = %u, size = %u, image size = %u\n",
+ i, offset, size, imageSize);
+ break;
+ }
+
+ if ((offset % alignment) != 0)
+ {
+ rc = TRACE_ERRORX(P9_XIP_ALIGNMENT_ERROR,
+ "Section %d requires %d-byte initial "
+ "alignment but the section offset is %u\n",
+ i, alignment, offset);
+ break;
+ }
+ }
+
+ if (rc)
+ {
+ break;
+ }
+
+ // If the TOC exists and the image is normalized, validate each TOC
+ // entry.
+
+ size = hostHeader.iv_section[P9_XIP_SECTION_TOC].iv_size;
+
+ if (size != 0)
+ {
+ if (xipNormalized(i_image))
+ {
+ rc = p9_xip_map_toc(i_image, xipValidateTocEntry, 0);
+
+ if (rc)
+ {
+ break;
+ }
+ }
+ }
+ }
+ while (0);
+
+ return rc;
+}
+
+
+int
+p9_xip_validate2(void* i_image, const uint32_t i_size, const uint32_t i_maskIgnores)
+{
+ P9XipHeader hostHeader;
+ int rc = 0, i;
+ uint32_t linkAddress, imageSize, extent, offset, size;
+ uint8_t alignment;
+
+ p9_xip_translate_header(&hostHeader, (P9XipHeader*)i_image);
+
+ do
+ {
+
+ // Validate C/Assembler constraints.
+
+ if (sizeof(P9XipSection) != SIZE_OF_P9_XIP_SECTION)
+ {
+ rc = TRACE_ERRORX(P9_XIP_BUG,
+ "C/Assembler size mismatch(%ld/%d) "
+ "for P9XipSection\n",
+ sizeof(P9XipSection), SIZE_OF_P9_XIP_SECTION);
+ break;
+ }
+
+ if (sizeof(P9XipToc) != SIZE_OF_P9_XIP_TOC)
+ {
+ rc = TRACE_ERRORX(P9_XIP_BUG,
+ "C/Assembler size mismatch(%ld/%d) "
+ "for P9XipToc\n",
+ sizeof(P9XipToc), SIZE_OF_P9_XIP_TOC);
+ break;
+ }
+
+ if (sizeof(P9XipHashedToc) != SIZE_OF_P9_XIP_HASHED_TOC)
+ {
+ rc = TRACE_ERRORX(P9_XIP_BUG,
+ "C/Assembler size mismatch(%ld/%d) "
+ "for P9XipHashedToc\n",
+ sizeof(P9XipHashedToc),
+ SIZE_OF_P9_XIP_HASHED_TOC);
+ break;
+ }
+
+ // Validate the image pointer and magic number
+
+ rc = xipQuickCheck(i_image, 0);
+
+ if (rc)
+ {
+ break;
+ }
+
+ // Validate the image size
+
+ linkAddress = hostHeader.iv_linkAddress;
+ imageSize = hostHeader.iv_imageSize;
+ extent = linkAddress + imageSize;
+
+ if (imageSize < sizeof(P9XipHeader))
+ {
+ rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR,
+ "p9_xip_validate2(%p, %u) : "
+ "The image size recorded in the image "
+ "(%u) is smaller than the header size.\n",
+ i_image, i_size, imageSize);
+ break;
+ }
+
+ if (imageSize != i_size && !(i_maskIgnores & P9_XIP_IGNORE_FILE_SIZE))
+ {
+ rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR,
+ "p9_xip_validate2(%p, %u) : "
+ "The image size recorded in the image "
+ "(%u) does not match the i_size parameter.\n",
+ i_image, i_size, imageSize);
+ break;
+ }
+
+ if (extent <= linkAddress)
+ {
+ rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR,
+ "p9_xip_validate2(%p, %u) : "
+ "Given the link address (%u) and the "
+ "image size, the image wraps the address space\n",
+ i_image, i_size, linkAddress);
+ break;
+ }
+
+ if ((imageSize % P9_XIP_FINAL_ALIGNMENT) != 0)
+ {
+ rc = TRACE_ERRORX(P9_XIP_ALIGNMENT_ERROR,
+ "p9_xip_validate2(%p, %u) : "
+ "The image size (%u) is not a multiple of %u\n",
+ i_image, i_size, imageSize,
+ P9_XIP_FINAL_ALIGNMENT);
+ break;
+ }
+
+ // Validate that all sections appear to be within the image
+ // bounds, and are aligned correctly.
+
+ for (i = 0; i < P9_XIP_SECTIONS; i++)
+ {
+
+ offset = hostHeader.iv_section[i].iv_offset;
+ size = hostHeader.iv_section[i].iv_size;
+ alignment = hostHeader.iv_section[i].iv_alignment;
+
+ if ((offset > imageSize) ||
+ ((offset + size) > imageSize) ||
+ ((offset + size) < offset))
+ {
+ rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR,
+ "Section %d does not appear to be within "
+ "the bounds of the image\n"
+ "offset = %u, size = %u, image size = %u\n",
+ i, offset, size, imageSize);
+ break;
+ }
+
+ if ((offset % alignment) != 0)
+ {
+ rc = TRACE_ERRORX(P9_XIP_ALIGNMENT_ERROR,
+ "Section %d requires %d-byte initial "
+ "alignment but the section offset is %u\n",
+ i, alignment, offset);
+ break;
+ }
+ }
+
+ if (rc)
+ {
+ break;
+ }
+
+ // If the TOC exists and the image is normalized, validate each TOC
+ // entry.
+
+ size = hostHeader.iv_section[P9_XIP_SECTION_TOC].iv_size;
+
+ if (size != 0)
+ {
+ if (xipNormalized(i_image))
+ {
+ rc = p9_xip_map_toc(i_image, xipValidateTocEntry, 0);
+
+ if (rc)
+ {
+ break;
+ }
+ }
+ }
+ }
+ while (0);
+
+ return rc;
+}
+
+
+// Normalization:
+//
+// 1. Normalize the TOC, unless the image is already normalized. The image
+// must be marked as normalized before sorting.
+//
+// 2. Sort the TOC.
+//
+// 3. Clear the section offsets of any empty sections to make the section
+// table reports less confusing.
+//
+// 4. Clear normalization status on any failure.
+
+int
+p9_xip_normalize(void* io_image)
+{
+ int rc, i;
+ P9XipSection section;
+ P9XipToc* imageToc;
+ P9XipHashedToc* fixedImageToc;
+ P9XipHashedToc* fixedTocEntry;
+ size_t tocEntries, fixedTocEntries, fixedEntriesRemaining;
+
+ do
+ {
+ rc = xipQuickCheck(io_image, 0);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (!xipNormalized(io_image))
+ {
+
+ rc = p9_xip_get_toc(io_image, &imageToc, &tocEntries, 0, 0);
+
+ if (rc)
+ {
+ break;
+ }
+
+ rc = xipGetFixedToc(io_image, &fixedImageToc, &fixedTocEntries);
+
+ if (rc)
+ {
+ break;
+ }
+
+ fixedTocEntry = fixedImageToc;
+ fixedEntriesRemaining = fixedTocEntries;
+
+ for (; tocEntries--; imageToc++)
+ {
+ rc = xipNormalizeToc(io_image, imageToc,
+ &fixedTocEntry, &fixedEntriesRemaining);
+
+ if (rc)
+ {
+ break;
+ }
+
+ }
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (fixedEntriesRemaining != 0)
+ {
+ rc = TRACE_ERRORX(P9_XIP_TOC_ERROR,
+ "Not enough TOC entries for .fixed");
+ break;
+ }
+
+ rc = xipHashCollision(fixedImageToc, fixedTocEntries);
+
+ if (rc)
+ {
+ break;
+ }
+
+ ((P9XipHeader*)io_image)->iv_normalized = 1;
+ }
+
+ rc = xipSortToc(io_image);
+
+ if (rc)
+ {
+ break;
+ }
+
+ for (i = 0; i < P9_XIP_SECTIONS; i++)
+ {
+ rc = p9_xip_get_section(io_image, i, &section);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (section.iv_size == 0)
+ {
+ xipSetSectionOffset(io_image, i, 0);
+ }
+ }
+
+ if (rc)
+ {
+ break;
+ }
+
+ }
+ while(0);
+
+ ((P9XipHeader*)io_image)->iv_normalized = (rc == 0);
+
+ return rc;
+}
+
+
+int
+p9_xip_image_size(void* io_image, uint32_t* o_size)
+{
+ int rc;
+
+ rc = xipQuickCheck(io_image, 0);
+
+ if (!rc)
+ {
+ *o_size = xipImageSize(io_image);
+ }
+
+ return rc;
+}
+
+
+int
+p9_xip_get_section(const void* i_image,
+ const int i_sectionId,
+ P9XipSection* o_hostSection)
+{
+ int rc;
+ P9XipSection* imageSection;
+
+ rc = xipGetSectionPointer(i_image, i_sectionId, &imageSection);
+
+ if (!rc)
+ {
+ xipTranslateSection(o_hostSection, imageSection);
+ }
+
+ return rc;
+}
+
+
+// If the 'big' TOC is not present, search the mini-TOCs that only index the
+// .fixed and .header sections.
+
+int
+p9_xip_find(void* i_image,
+ const char* i_id,
+ P9XipItem* o_item)
+{
+ int rc;
+ P9XipToc* toc;
+ P9XipItem item, *pitem;
+ P9XipSection* tocSection;
+
+ do
+ {
+ rc = xipQuickCheck(i_image, 1);
+
+ if (rc)
+ {
+ break;
+ }
+
+ rc = xipGetSectionPointer(i_image, P9_XIP_SECTION_TOC, &tocSection);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (tocSection->iv_size == 0)
+ {
+ rc = xipFixedFind(i_image, i_id, o_item);
+
+ if (rc)
+ {
+ rc = xipHeaderFind(i_image, i_id, o_item);
+ }
+
+ break;
+ }
+
+ if (xipSorted(i_image))
+ {
+ rc = xipBinarySearch(i_image, i_id, &toc);
+ }
+ else
+ {
+ rc = xipLinearSearch(i_image, i_id, &toc);
+ }
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (o_item)
+ {
+ pitem = o_item;
+ }
+ else
+ {
+ pitem = &item;
+ }
+
+ rc = xipDecodeToc(i_image, toc, pitem);
+
+ if (rc)
+ {
+ break;
+ }
+
+ }
+ while (0);
+
+ return rc;
+}
+
+int
+p9_xip_get_item(const P9XipItem* i_item, uint64_t* o_data)
+{
+ switch (i_item->iv_type)
+ {
+ case P9_XIP_UINT8:
+ *o_data = *((uint8_t*)(i_item->iv_imageData));
+ break;
+
+ case P9_XIP_UINT16:
+ *o_data = htobe16(*((uint16_t*)(i_item->iv_imageData)));
+ break;
+
+ case P9_XIP_UINT32:
+ *o_data = htobe32(*((uint32_t*)(i_item->iv_imageData)));
+ break;
+
+ case P9_XIP_UINT64:
+ *o_data = htobe64(*((uint64_t*)(i_item->iv_imageData)));
+ break;
+
+ case P9_XIP_INT8:
+ *o_data = *((int8_t*)(i_item->iv_imageData));
+ break;
+
+ case P9_XIP_INT16:
+ *o_data = htobe16(*((int16_t*)(i_item->iv_imageData)));
+ break;
+
+ case P9_XIP_INT32:
+ *o_data = htobe32(*((int32_t*)(i_item->iv_imageData)));
+ break;
+
+ case P9_XIP_INT64:
+ *o_data = htobe64(*((int64_t*)(i_item->iv_imageData)));
+ break;
+
+ case P9_XIP_ADDRESS:
+ *o_data = i_item->iv_address;
+ break;
+
+ case P9_XIP_STRING:
+ //Nothing to do in case of string, but making sure rc is valid
+ break;
+
+ default:
+ return TRACE_ERROR(P9_XIP_TYPE_ERROR);
+ break;
+ }
+
+ return 0;
+}
+
+int
+p9_xip_get_scalar(void* i_image, const char* i_id, uint64_t* o_data)
+{
+ int rc;
+ P9XipItem item;
+
+ rc = p9_xip_find(i_image, i_id, &item);
+
+ if (!rc)
+ {
+ rc = p9_xip_get_item(&item, o_data);
+ }
+
+ return rc;
+}
+
+int
+p9_xip_get_element(void* i_image,
+ const char* i_id,
+ const uint32_t i_index,
+ uint64_t* o_data)
+{
+ int rc;
+ P9XipItem item;
+
+ do
+ {
+ rc = p9_xip_find(i_image, i_id, &item);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if ((item.iv_elements != 0) && (i_index >= item.iv_elements))
+ {
+ rc = TRACE_ERROR(P9_XIP_BOUNDS_ERROR);
+ break;
+ }
+
+ switch (item.iv_type)
+ {
+ case P9_XIP_UINT8:
+ *o_data = ((uint8_t*)(item.iv_imageData))[i_index];
+ break;
+
+ case P9_XIP_UINT16:
+ *o_data = htobe16(((uint16_t*)(item.iv_imageData))[i_index]);
+ break;
+
+ case P9_XIP_UINT32:
+ *o_data = htobe32(((uint32_t*)(item.iv_imageData))[i_index]);
+ break;
+
+ case P9_XIP_UINT64:
+ *o_data = htobe64(((uint64_t*)(item.iv_imageData))[i_index]);
+ break;
+
+ case P9_XIP_INT8:
+ *o_data = ((int8_t*)(item.iv_imageData))[i_index];
+ break;
+
+ case P9_XIP_INT16:
+ *o_data = htobe16(((int16_t*)(item.iv_imageData))[i_index]);
+ break;
+
+ case P9_XIP_INT32:
+ *o_data = htobe32(((int32_t*)(item.iv_imageData))[i_index]);
+ break;
+
+ case P9_XIP_INT64:
+ *o_data = htobe64(((int64_t*)(item.iv_imageData))[i_index]);
+ break;
+
+ default:
+ rc = TRACE_ERROR(P9_XIP_TYPE_ERROR);
+ break;
+ }
+
+ if (rc)
+ {
+ break;
+ }
+
+ }
+ while (0);
+
+ return rc;
+}
+
+
+int
+p9_xip_get_string(void* i_image, const char* i_id, char** o_data)
+{
+ int rc;
+ P9XipItem item;
+
+ rc = p9_xip_find(i_image, i_id, &item);
+
+ if (!rc)
+ {
+ switch (item.iv_type)
+ {
+ case P9_XIP_STRING:
+ *o_data = (char*)(item.iv_imageData);
+ break;
+
+ default:
+ rc = TRACE_ERROR(P9_XIP_TYPE_ERROR);
+ break;
+ }
+ }
+
+ return rc;
+}
+
+
+int
+p9_xip_read_uint64(const void* i_image,
+ const uint64_t i_imageAddress,
+ uint64_t* o_data)
+{
+ int rc;
+
+ do
+ {
+ rc = xipQuickCheck(i_image, 0);
+
+ if (rc)
+ {
+ break;
+ }
+
+ rc = xipValidateImageAddress(i_image, i_imageAddress, 8);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (i_imageAddress % 8)
+ {
+ rc = TRACE_ERROR(P9_XIP_ALIGNMENT_ERROR);
+ break;
+ }
+
+ *o_data =
+ htobe64(*((uint64_t*)xipImage2Host(i_image, i_imageAddress)));
+
+ }
+ while(0);
+
+ return rc;
+}
+
+
+int
+p9_xip_set_scalar(void* io_image, const char* i_id, const uint64_t i_data)
+{
+ int rc;
+ P9XipItem item;
+
+ rc = p9_xip_find(io_image, i_id, &item);
+
+ if (!rc)
+ {
+ switch(item.iv_type)
+ {
+ case P9_XIP_UINT8:
+ *((uint8_t*)(item.iv_imageData)) = (uint8_t)i_data;
+ break;
+
+ case P9_XIP_UINT16:
+ *((uint16_t*)(item.iv_imageData)) = htobe16((uint16_t)i_data);
+ break;
+
+ case P9_XIP_UINT32:
+ *((uint32_t*)(item.iv_imageData)) = htobe32((uint32_t)i_data);
+ break;
+
+ case P9_XIP_UINT64:
+ *((uint64_t*)(item.iv_imageData)) = htobe64((uint64_t)i_data);
+ break;
+
+ case P9_XIP_INT8:
+ *((int8_t*)(item.iv_imageData)) = (int8_t)i_data;
+ break;
+
+ case P9_XIP_INT16:
+ *((int16_t*)(item.iv_imageData)) = htobe16((int16_t)i_data);
+ break;
+
+ case P9_XIP_INT32:
+ *((int32_t*)(item.iv_imageData)) = htobe32((int32_t)i_data);
+ break;
+
+ case P9_XIP_INT64:
+ *((int64_t*)(item.iv_imageData)) = htobe64((int64_t)i_data);
+ break;
+
+ default:
+ rc = TRACE_ERROR(P9_XIP_TYPE_ERROR);
+ break;
+ }
+ }
+
+ return rc;
+}
+
+
+int
+p9_xip_set_element(void* i_image,
+ const char* i_id,
+ const uint32_t i_index,
+ const uint64_t i_data)
+{
+ int rc;
+ P9XipItem item;
+
+ do
+ {
+ rc = p9_xip_find(i_image, i_id, &item);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if ((item.iv_elements != 0) && (i_index >= item.iv_elements))
+ {
+ rc = TRACE_ERROR(P9_XIP_BOUNDS_ERROR);
+ break;
+ }
+
+ switch (item.iv_type)
+ {
+ case P9_XIP_UINT8:
+ ((uint8_t*)(item.iv_imageData))[i_index] = (uint8_t)i_data;
+ break;
+
+ case P9_XIP_UINT16:
+ ((uint16_t*)(item.iv_imageData))[i_index] =
+ htobe16((uint16_t)i_data);
+ break;
+
+ case P9_XIP_UINT32:
+ ((uint32_t*)(item.iv_imageData))[i_index] =
+ htobe32((uint32_t)i_data);
+ break;
+
+ case P9_XIP_UINT64:
+ ((uint64_t*)(item.iv_imageData))[i_index] =
+ htobe64((uint64_t)i_data);
+ break;
+
+ case P9_XIP_INT8:
+ ((int8_t*)(item.iv_imageData))[i_index] = (int8_t)i_data;
+ break;
+
+ case P9_XIP_INT16:
+ ((int16_t*)(item.iv_imageData))[i_index] =
+ htobe16((uint16_t)i_data);
+ break;
+
+ case P9_XIP_INT32:
+ ((int32_t*)(item.iv_imageData))[i_index] =
+ htobe32((uint32_t)i_data);
+ break;
+
+ case P9_XIP_INT64:
+ ((int64_t*)(item.iv_imageData))[i_index] =
+ htobe64((uint64_t)i_data);
+ break;
+
+ default:
+ rc = TRACE_ERROR(P9_XIP_TYPE_ERROR);
+ break;
+ }
+
+ if (rc)
+ {
+ break;
+ }
+
+ }
+ while (0);
+
+ return rc;
+}
+
+
+int
+p9_xip_set_string(void* i_image, const char* i_id, const char* i_data)
+{
+ int rc;
+ P9XipItem item;
+ char* dest;
+
+ rc = p9_xip_find(i_image, i_id, &item);
+
+ if (!rc)
+ {
+ switch (item.iv_type)
+ {
+ case P9_XIP_STRING:
+ dest = (char*)(item.iv_imageData);
+
+ if (strlen(dest) < strlen(i_data))
+ {
+ memcpy(dest, i_data, strlen(dest));
+ }
+ else
+ {
+ strcpy(dest, i_data);
+ }
+
+ break;
+
+ default:
+ rc = TRACE_ERROR(P9_XIP_TYPE_ERROR);
+ break;
+ }
+ }
+
+ return rc;
+}
+
+
+int
+p9_xip_write_uint64(void* io_image,
+ const uint64_t i_imageAddress,
+ const uint64_t i_data)
+{
+ int rc;
+
+ do
+ {
+ rc = xipQuickCheck(io_image, 0);
+
+ if (rc)
+ {
+ break;
+ }
+
+ rc = xipValidateImageAddress(io_image, i_imageAddress, 8);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (i_imageAddress % 8)
+ {
+ rc = TRACE_ERROR(P9_XIP_ALIGNMENT_ERROR);
+ break;
+ }
+
+ *((uint64_t*)xipImage2Host(io_image, i_imageAddress)) =
+ htobe64(i_data);
+
+ }
+ while(0);
+
+ return rc;
+}
+
+
+int
+p9_xip_delete_section(void* io_image,
+ void* o_imageBuf,
+ const uint32_t i_imageBufSize,
+ const int i_sectionId)
+{
+ int rc, final;
+ P9XipSection section;
+ size_t imageSize;
+ uint8_t bImageChanged = 0; // Tracks if io_image has been modified.
+
+ do
+ {
+
+ // Get image size. We'll need it a lot.
+
+ imageSize = xipImageSize(io_image);
+
+ // Parm check 1: imageBufSize
+ // - Must be >=imageSize for a valid imageBuf buffer
+
+ if (i_imageBufSize < imageSize && o_imageBuf != NULL)
+ {
+ rc = TRACE_ERRORX(P9_XIP_WOULD_OVERFLOW,
+ "xip_delete_section(): imageBufSize too small");
+ break;
+ }
+
+ // Parm check 2: sectionId
+ // - It is illegal to remove the .header. It would kill the image.
+
+ if (i_sectionId == P9_XIP_SECTION_HEADER)
+ {
+ rc = TRACE_ERRORX(P9_XIP_SECTION_ERROR,
+ "xip_delete_section(): It is illegal to remove .header");
+ break;
+ }
+
+ // Copy io_image to o_imageBuf if a valid imageBuf ptr is
+ // supplied, i.e., imageBuf!=NULL. We'll need a reference copy
+ // of any delected section to be re-appended after the section
+ // delete process is done.
+ if (o_imageBuf != NULL)
+ {
+ // We always return a copy of the original input image.
+ memcpy(o_imageBuf, io_image, imageSize);
+ }
+
+ // Check the image
+
+ rc = xipQuickCheck(io_image, 1);
+
+ if (rc)
+ {
+ break;
+ }
+
+ // Deleting an empty section is a NOP. Otherwise the section must be
+ // the final section of the image. Update the sizes and re-establish
+ // the final image alignment.
+
+ rc = p9_xip_get_section(io_image, i_sectionId, &section);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (section.iv_size == 0)
+ {
+ break;
+ }
+
+ // Determine last image section.
+
+ rc = xipFinalSection(io_image, &final);
+
+ if (rc)
+ {
+ break;
+ }
+
+ // Now, delete necessary sections in order of highest section offset
+ // to the offset of the section, i_sectionId, to be removed.
+
+ if (final == i_sectionId)
+ {
+ rc = xipDeleteLastSection(io_image, i_sectionId);
+
+ bImageChanged = 1;
+
+ break;
+ }
+ else
+ {
+ // Check for imageBuf ptr violation. If this fails, this is
+ // catastrophic since we don't have a reference copy of the input
+ // image (i.e, the memcpy of the image earlier wasn't executed.)
+
+ if (o_imageBuf == NULL)
+ {
+ rc = TRACE_ERRORX(P9_XIP_NULL_BUFFER,
+ "xip_delete_section(): Can't copy image into NULL buffer\n");
+ break;
+ }
+
+ // Delete sections, in order, that have offset addresses higher
+ // than i_sectionId and make a note of the order which is to
+ // be used when re-appending. Then delete i_sectionId.
+
+ uint8_t sectionOrder[P9_XIP_SECTIONS];
+ uint8_t orderIdx = 0;
+
+ do
+ {
+
+ rc = xipFinalSection(io_image, &final);
+
+ if (rc)
+ {
+ break;
+ }
+
+ // It is illegal to remove .header. It would kill the image.
+ if (final == P9_XIP_SECTION_HEADER)
+ {
+ rc = TRACE_ERRORX(P9_XIP_SECTION_ERROR,
+ "xip_delete_section(): Code bug: Attempt to remove .header");
+ break;
+ }
+
+ if (final != i_sectionId)
+ {
+ sectionOrder[orderIdx] = final;
+ orderIdx++;
+ }
+
+ rc = xipDeleteLastSection(io_image, final);
+
+ bImageChanged = 1;
+
+ if (rc)
+ {
+ break;
+ }
+
+ }
+ while (final != i_sectionId);
+
+ if (rc)
+ {
+ break;
+ }
+
+ // Reappend previously deleted sections in original order
+
+ do
+ {
+
+ orderIdx--;
+ rc = p9_xip_get_section(o_imageBuf, sectionOrder[orderIdx], &section);
+
+ if (rc)
+ {
+ break;
+ }
+
+ rc = p9_xip_append( io_image,
+ sectionOrder[orderIdx],
+ (void*)(((uint8_t*)o_imageBuf) + section.iv_offset),
+ (const uint32_t)section.iv_size,
+ (const uint32_t)imageSize,
+ NULL );
+
+ if (rc)
+ {
+ break;
+ }
+
+ }
+ while (orderIdx);
+
+ break;
+ }
+
+ }
+ while (0);
+
+ // Restore broken input image in case of rc!=0. But only do so if input
+ // image has changed.
+
+ if (rc && bImageChanged)
+ {
+ memcpy(io_image, o_imageBuf, imageSize);
+ }
+
+ return rc;
+}
+
+
+#ifndef PPC_HYP
+
+// This API is not needed by PHYP procedures, and is elided since PHYP does
+// not support malloc().
+
+int
+p9_xip_duplicate_section(const void* i_image,
+ const int i_sectionId,
+ void** o_duplicate,
+ uint32_t* o_size)
+{
+ P9XipSection section;
+ int rc;
+
+ *o_duplicate = 0;
+
+ do
+ {
+ rc = xipQuickCheck(i_image, 0);
+
+ if (rc)
+ {
+ break;
+ }
+
+ rc = p9_xip_get_section(i_image, i_sectionId, &section);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (section.iv_size == 0)
+ {
+ rc = TRACE_ERRORX(P9_XIP_SECTION_ERROR,
+ "Attempt to duplicate empty section %d\n",
+ i_sectionId);
+ break;
+ }
+
+ *o_duplicate = malloc(section.iv_size);
+ *o_size = section.iv_size;
+
+ if (*o_duplicate == 0)
+ {
+ rc = TRACE_ERROR(P9_XIP_NO_MEMORY);
+ break;
+ }
+
+ memcpy(*o_duplicate,
+ xipHostAddressFromOffset(i_image, section.iv_offset),
+ section.iv_size);
+
+
+ }
+ while (0);
+
+ if (rc)
+ {
+ free(*o_duplicate);
+ *o_duplicate = 0;
+ *o_size = 0;
+ }
+
+ return rc;
+}
+
+#endif // PPC_HYP
+
+
+// The append must be done in such a way that if the append fails, the image
+// is not modified. This behavior is required by applications that
+// speculatively append until the allocation fails, but still require the
+// final image to be valid. To accomplish this the initial image size and
+// section statistics are captured at entry, and restored in the event of an
+// error.
+
+int
+p9_xip_append(void* io_image,
+ const int i_sectionId,
+ const void* i_data,
+ const uint32_t i_size,
+ const uint32_t i_allocation,
+ uint32_t* o_sectionOffset)
+{
+ P9XipSection section, initialSection;
+ int rc, final, restoreOnError;
+ void* hostAddress;
+ uint32_t pad, initialSize;
+
+ do
+ {
+ restoreOnError = 0;
+
+ rc = xipQuickCheck(io_image, 1);
+
+ if (rc)
+ {
+ break;
+ }
+
+ rc = p9_xip_get_section(io_image, i_sectionId, &section);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (i_size == 0)
+ {
+ break;
+ }
+
+ initialSection = section;
+ initialSize = xipImageSize(io_image);
+ restoreOnError = 1;
+
+ if (section.iv_size == 0)
+ {
+
+ // The section is empty, and now becomes the final section. Pad
+ // the image to the specified section alignment. Note that the
+ // size of the previously final section does not change.
+
+ rc = xipPadImage(io_image, i_allocation, section.iv_alignment,
+ &pad);
+
+ if (rc)
+ {
+ break;
+ }
+
+ section.iv_offset = xipImageSize(io_image);
+
+ }
+ else
+ {
+
+ // Otherwise, the section must be the final section in order to
+ // continue. Remove any padding from the image.
+
+ rc = xipFinalSection(io_image, &final);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (final != i_sectionId)
+ {
+ rc = TRACE_ERRORX(P9_XIP_SECTION_ERROR,
+ "Attempt to append to non-final section "
+ "%d\n", i_sectionId);
+ break;
+ }
+
+ xipSetImageSize(io_image, section.iv_offset + section.iv_size);
+ }
+
+
+ // Make sure the allocated space won't overflow. Set the return
+ // parameter o_sectionOffset and copy the new data into the image (or
+ // simply clear the space).
+
+ if ((xipImageSize(io_image) + i_size) > i_allocation)
+ {
+ rc = TRACE_ERROR(P9_XIP_WOULD_OVERFLOW);
+ break;
+ }
+
+ if (o_sectionOffset != 0)
+ {
+ *o_sectionOffset = section.iv_size;
+ }
+
+ hostAddress =
+ xipHostAddressFromOffset(io_image, xipImageSize(io_image));
+
+ if (i_data == 0)
+ {
+ memset(hostAddress, 0, i_size);
+ }
+ else
+ {
+ memcpy(hostAddress, i_data, i_size);
+ }
+
+
+ // Update the image size and section table. Note that the final
+ // alignment may push out of the allocation.
+
+ xipSetImageSize(io_image, xipImageSize(io_image) + i_size);
+ xipFinalAlignment(io_image);
+
+ if (xipImageSize(io_image) > i_allocation)
+ {
+ rc = TRACE_ERROR(P9_XIP_WOULD_OVERFLOW);
+ break;
+ }
+
+ section.iv_size += i_size;
+
+ if (xipPutSection(io_image, i_sectionId, &section) != 0)
+ {
+ rc = TRACE_ERROR(P9_XIP_BUG); /* Can't happen */
+ break;
+ }
+
+
+ // Special case
+
+ if (i_sectionId == P9_XIP_SECTION_TOC)
+ {
+ ((P9XipHeader*)io_image)->iv_tocSorted = 0;
+ }
+
+ }
+ while (0);
+
+ if (rc && restoreOnError)
+ {
+ if (xipPutSection(io_image, i_sectionId, &initialSection) != 0)
+ {
+ rc = TRACE_ERROR(P9_XIP_BUG); /* Can't happen */
+ }
+
+ xipSetImageSize(io_image, initialSize);
+ }
+
+ return rc;
+}
+
+
+int
+p9_xip_section2image(const void* i_image,
+ const int i_sectionId,
+ const uint32_t i_offset,
+ uint64_t* o_imageAddress)
+{
+ int rc;
+ P9XipSection section;
+
+ do
+ {
+ rc = xipQuickCheck(i_image, 0);
+
+ if (rc)
+ {
+ break;
+ }
+
+ rc = p9_xip_get_section(i_image, i_sectionId, &section);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (section.iv_size == 0)
+ {
+ rc = TRACE_ERROR(P9_XIP_SECTION_ERROR);
+ break;
+ }
+
+ if (i_offset > (section.iv_offset + section.iv_size))
+ {
+ rc = TRACE_ERROR(P9_XIP_INVALID_ARGUMENT);
+ break;
+ }
+
+ *o_imageAddress = xipLinkAddress(i_image) + section.iv_offset + i_offset;
+
+ if (*o_imageAddress % 4)
+ {
+ rc = TRACE_ERROR(P9_XIP_ALIGNMENT_ERROR);
+ break;
+ }
+
+ }
+ while(0);
+
+ return rc;
+}
+
+
+int
+p9_xip_image2section(const void* i_image,
+ const uint64_t i_imageAddress,
+ int* i_section,
+ uint32_t* i_offset)
+{
+ int rc;
+
+ do
+ {
+ rc = xipQuickCheck(i_image, 0);
+
+ if (rc)
+ {
+ break;
+ }
+
+ rc = xipImage2Section(i_image, i_imageAddress, i_section, i_offset);
+
+ }
+ while(0);
+
+ return rc;
+}
+
+
+int
+p9_xip_image2host(const void* i_image,
+ const uint64_t i_imageAddress,
+ void** o_hostAddress)
+{
+ int rc;
+
+ do
+ {
+ rc = xipQuickCheck(i_image, 0);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if ((i_imageAddress < xipLinkAddress(i_image)) ||
+ (i_imageAddress >
+ (xipLinkAddress(i_image) + xipImageSize(i_image))))
+ {
+ rc = TRACE_ERROR(P9_XIP_INVALID_ARGUMENT);
+ break;
+ }
+
+ *o_hostAddress =
+ xipHostAddressFromOffset(i_image,
+ i_imageAddress - xipLinkAddress(i_image));
+ }
+ while(0);
+
+ return rc;
+}
+
+
+int
+p9_xip_host2image(const void* i_image,
+ void* i_hostAddress,
+ uint64_t* o_imageAddress)
+{
+ int rc;
+
+ do
+ {
+ rc = xipQuickCheck(i_image, 0);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if ((i_hostAddress < i_image) ||
+ (i_hostAddress >
+ xipHostAddressFromOffset(i_image, xipImageSize(i_image))))
+ {
+ rc = TRACE_ERROR(P9_XIP_INVALID_ARGUMENT);
+ break;
+ }
+
+ *o_imageAddress = xipLinkAddress(i_image) +
+ ((unsigned long)i_hostAddress - (unsigned long)i_image);
+
+ if (*o_imageAddress % 4)
+ {
+ rc = TRACE_ERROR(P9_XIP_ALIGNMENT_ERROR);
+ break;
+ }
+ }
+ while(0);
+
+ return rc;
+}
+
+
+void
+p9_xip_translate_header(P9XipHeader* o_dest, const P9XipHeader* i_src)
+{
+#ifndef _BIG_ENDIAN
+ int i;
+ P9XipSection* destSection;
+ const P9XipSection* srcSection;
+
+#if P9_XIP_HEADER_VERSION != 9
+#error This code assumes the P9-XIP header version 9 layout
+#endif
+
+ o_dest->iv_magic = htobe64(i_src->iv_magic);
+ o_dest->iv_L1LoaderAddr = htobe64(i_src->iv_L1LoaderAddr);
+ o_dest->iv_L2LoaderAddr = htobe64(i_src->iv_L2LoaderAddr);
+ o_dest->iv_kernelAddr = htobe64(i_src->iv_kernelAddr);
+ o_dest->iv_linkAddress = htobe64(i_src->iv_linkAddress);
+
+ for (i = 0; i < 3; i++)
+ {
+ o_dest->iv_reserved64[i] = 0;
+ }
+
+ for (i = 0, destSection = o_dest->iv_section,
+ srcSection = i_src->iv_section;
+ i < P9_XIP_SECTIONS;
+ i++, destSection++, srcSection++)
+ {
+ xipTranslateSection(destSection, srcSection);
+ }
+
+ o_dest->iv_imageSize = htobe32(i_src->iv_imageSize);
+ o_dest->iv_buildDate = htobe32(i_src->iv_buildDate);
+ o_dest->iv_buildTime = htobe32(i_src->iv_buildTime);
+
+ for (i = 0; i < 5; i++)
+ {
+ o_dest->iv_reserved32[i] = 0;
+ }
+
+ o_dest->iv_headerVersion = i_src->iv_headerVersion;
+ o_dest->iv_normalized = i_src->iv_normalized;
+ o_dest->iv_tocSorted = i_src->iv_tocSorted;
+
+ for (i = 0; i < 3; i++)
+ {
+ o_dest->iv_reserved8[i] = 0;
+ }
+
+ memcpy(o_dest->iv_buildUser, i_src->iv_buildUser,
+ sizeof(i_src->iv_buildUser));
+ memcpy(o_dest->iv_buildHost, i_src->iv_buildHost,
+ sizeof(i_src->iv_buildHost));
+ memcpy(o_dest->iv_reservedChar, i_src->iv_reservedChar,
+ sizeof(i_src->iv_reservedChar));
+
+#else
+
+ if (o_dest != i_src)
+ {
+ *o_dest = *i_src;
+ }
+
+#endif /* _BIG_ENDIAN */
+}
+
+
+int
+p9_xip_map_toc(void* io_image,
+ int (*i_fn)(void* io_image,
+ const P9XipItem* i_item,
+ void* io_arg),
+ void* io_arg)
+{
+ int rc;
+ P9XipToc* imageToc;
+ P9XipItem item;
+ size_t entries;
+
+ do
+ {
+ rc = xipQuickCheck(io_image, 0);
+
+ if (rc)
+ {
+ break;
+ }
+
+ rc = p9_xip_get_toc(io_image, &imageToc, &entries, 0, 0);
+
+ if (rc)
+ {
+ break;
+ }
+
+ for (; entries--; imageToc++)
+ {
+ rc = xipDecodeToc(io_image, imageToc, &item);
+
+ if (rc)
+ {
+ break;
+ }
+
+ rc = i_fn(io_image, &item, io_arg);
+
+ if (rc)
+ {
+ break;
+ }
+ }
+ }
+ while(0);
+
+ return rc;
+}
diff --git a/src/import/chips/p9/xip/p9_xip_image.h b/src/import/chips/p9/xip/p9_xip_image.h
new file mode 100644
index 00000000..09bc1aa5
--- /dev/null
+++ b/src/import/chips/p9/xip/p9_xip_image.h
@@ -0,0 +1,1925 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: import/chips/p9/xip/p9_xip_image.h $ */
+/* */
+/* OpenPOWER sbe Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015,2016 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+/// \file p9_xip_image.h
+/// \brief definition of structs in sections
+///
+/// Contains struct ProcSbeFixed which contains functions, rings and
+/// attributes whose pointers are stored in the fixed and fixed_toc section
+/// Everything related to creating and manipulating P9-XIP binary images
+
+// *INDENT-OFF*
+
+#ifndef __P9_XIP_IMAGE_H
+#define __P9_XIP_IMAGE_H
+
+/// Current version (fields, layout, sections) of the P9_XIP header
+///
+/// If any changes are made to this file or to p9_xip_header.H, please update
+/// the header version and follow-up on all of the error messages.
+
+#define P9_XIP_HEADER_VERSION 9
+
+/// \defgroup p9_xip_magic_numbers P9-XIP magic numbers
+///
+/// An P9-XIP magic number is a 64-bit constant. The 4 high-order bytes
+/// contain the ASCII characters "XIP " and identify the image as a P9-XIP
+/// image, while the 4 low-order bytes identify the type of the image.
+///
+/// @{
+
+#ifdef __ASSEMBLER__
+ #define ULL(x) x
+#else
+ #define ULL(x) x##ull
+#endif
+
+#define P9_XIP_MAGIC 0x58495020 // "XIP "
+#define P9_XIP_MAGIC_BASE ULL(0x5849502042415345) // "XIP BASE"
+#define P9_XIP_MAGIC_SEEPROM ULL(0x584950205345504d) // "XIP SEPM"
+#define P9_XIP_MAGIC_CENTAUR ULL(0x58495020434e5452) // "XIP CNTR"
+#define P9_XIP_MAGIC_HW ULL(0x5849502020204857) // "XIP HW"
+#define P9_XIP_MAGIC_SGPE ULL(0x5849502053475045) // "XIP SGPE"
+#define P9_XIP_MAGIC_RESTORE ULL(0x5849502052455354) // "XIP REST"
+#define P9_XIP_MAGIC_CME ULL(0x5849502020434d45) // "XIP CME"
+#define P9_XIP_MAGIC_PGPE ULL(0x5849502050475045) // "XIP PGPE"
+#define P9_XIP_MAGIC_IOPPE ULL(0x5849502049505045) // "XIP IPPE"
+#define P9_XIP_MAGIC_FPPE ULL(0x5849502046505045) // "XIP FPPE"
+
+/// @}
+
+
+/// \defgroup p9_xip_sections P9-XIP Image Section Indexes
+///
+/// These constants define the order that the P9XipSection structures appear
+/// in the header, which is not necessarily the order the sections appear in
+/// the binary image. Given that P9-XIP image contents are tightly
+/// controlled, we use this simple indexing scheme for the allowed sections
+/// rather than a more general approach, e.g., allowing arbitrary sections
+/// identified by their names.
+///
+/// @{
+
+// fixed number of entries in section table including common and
+// image-specific sections
+#define P9_XIP_SECTIONS 15
+
+// this ensures that common sections go first followed by image-specific
+// sections, to be used to define image-specific sections
+#define P9_XIP_SECTIONS_PLUS(num) (P9_XIP_SECTIONS_COMMON + num)
+
+#ifndef __ASSEMBLER__
+
+// these are common P9-XIP sections defined for a images
+typedef enum {
+ P9_XIP_SECTION_HEADER = 0,
+ P9_XIP_SECTION_FIXED = 1,
+ P9_XIP_SECTION_FIXED_TOC = 2,
+ P9_XIP_SECTION_TOC = 3,
+ P9_XIP_SECTION_STRINGS = 4,
+ P9_XIP_SECTIONS_COMMON = 5 // total number of common sections
+} p9_xip_section_common_t;
+
+/// Applications can expand this macro to create an array of section names.
+#define P9_XIP_SECTION_NAMES_COMMON \
+ ".header", \
+ ".fixed", \
+ ".fixedtoc", \
+ ".toc", \
+ ".strings"
+
+#define P9_XIP_SECTION_NAMES(var, ...) \
+ const char* var[] = { \
+ P9_XIP_SECTION_NAMES_COMMON, \
+ __VA_ARGS__ \
+ }
+
+/// Applications can use this macro to safely index the array of section
+/// names.
+#define P9_XIP_SECTION_NAME(var, n) \
+ ((((n) < 0) || ((n) >= (int)(sizeof(var) / sizeof(char*)))) ? \
+ "" : var[n])
+
+#endif /* __ASSEMBLER__ */
+
+/// @}
+
+
+/// \defgroup p9_xip_validate() ignore masks.
+///
+/// These defines, when matched in p9_xip_validate(), cause the validation
+/// to skip the check of the corresponding property. The purpose is to more
+/// effectively debug images that may be damaged and which have excess info
+/// before or after the image. The latter will be the case when dumping the
+/// image as a memory block without knowing where the image starts and ends.
+///
+/// @{
+
+#define P9_XIP_IGNORE_FILE_SIZE (uint32_t)0x00000001
+#define P9_XIP_IGNORE_ALL (uint32_t)0x80000000
+
+/// @}
+
+/// Maximum section alignment for P9-XIP sections
+#define P9_XIP_MAX_SECTION_ALIGNMENT 128
+
+/// \defgroup p9_xip_toc_types P9-XIP Table of Contents data types
+///
+/// These are the data types stored in the \a iv_type field of the P9XipToc
+/// objects. These must be defined as manifest constants because they are
+/// required to be recognized as manifest constants in C (as opposed to C++)
+/// code.
+///
+/// NB: The 0x0 code is purposefully left undefined to catch bugs.
+///
+/// @{
+
+/// Data is a single unsigned byte
+#define P9_XIP_UINT8 0x01
+
+/// Data is a 16-bit unsigned integer
+#define P9_XIP_UINT16 0x02
+
+/// Data is a 32-bit unsigned integer
+#define P9_XIP_UINT32 0x03
+
+/// Data is a 64-bit unsigned integer
+#define P9_XIP_UINT64 0x04
+
+/// Data is a single signed byte
+#define P9_XIP_INT8 0x05
+
+/// Data is a 16-bit signed integer
+#define P9_XIP_INT16 0x06
+
+/// Data is a 32-bit signed integer
+#define P9_XIP_INT32 0x07
+
+/// Data is a 64-bit signed integer
+#define P9_XIP_INT64 0x08
+
+/// Data is a 0-byte terminated ASCII string
+#define P9_XIP_STRING 0x09
+
+/// Data is an address
+#define P9_XIP_ADDRESS 0x0A
+
+/// The maximum type number
+#define P9_XIP_MAX_TYPE_INDEX 0x0A
+
+/// Applications can expand this macro to get access to string forms of the
+/// P9-XIP data types if desired.
+#define P9_XIP_TYPE_STRINGS(var) \
+ const char* var[] = { \
+ "Illegal 0 Code", \
+ "P9_XIP_UINT8", \
+ "P9_XIP_UINT16", \
+ "P9_XIP_UINT32", \
+ "P9_XIP_UINT64", \
+ "P9_XIP_INT8", \
+ "P9_XIP_INT16", \
+ "P9_XIP_INT32", \
+ "P9_XIP_INT64", \
+ "P9_XIP_STRING", \
+ "P9_XIP_ADDRESS", \
+ }
+
+/// Applications can expand this macro to get access to abbreviated string
+/// forms of the P9-XIP data types if desired.
+#define P9_XIP_TYPE_ABBREVS(var) \
+ const char* var[] = { \
+ "Illegal 0 Code", \
+ "u8 ", \
+ "u16", \
+ "u32", \
+ "u64", \
+ "i8 ", \
+ "i16", \
+ "i32", \
+ "i64", \
+ "str", \
+ "adr", \
+ }
+
+/// Applications can use this macro to safely index either array of P9-XIP
+/// type strings.
+#define P9_XIP_TYPE_STRING(var, n) \
+ (((n) > (sizeof(var) / sizeof(char*))) ? \
+ "Invalid P9-XIP type specification" : var[n])
+
+/// @}
+
+
+/// Final alignment constraint for P9-XIP images.
+///
+/// images are required to be multiples of 8 bytes in length, to
+/// gaurantee that the something will be able to complete any 8-byte load/store.
+#define P9_XIP_FINAL_ALIGNMENT 8
+
+
+////////////////////////////////////////////////////////////////////////////
+// C Definitions
+////////////////////////////////////////////////////////////////////////////
+
+#ifndef __ASSEMBLER__
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if 0
+} /* So __cplusplus doesn't mess w/auto-indent */
+#endif
+
+/// P9-XIP Section information
+///
+/// This structure defines the data layout of section table entries in the
+/// P9-XIP image header.
+
+// -*- DO NOT REORDER OR EDIT THIS STRUCTURE DEFINITION WITHOUT ALSO -*-
+// -*- EDITING THE ASSEMBLER LAYOUT IN p9_xip_header.H -*-
+
+typedef struct
+{
+
+ /// The offset (in bytes) of the section from the beginning of the image
+ ///
+ /// In normalized images the section offset will always be 0 if the
+ /// section size is also 0.
+ uint32_t iv_offset;
+
+ /// The size of the section in bytes, exclusive of alignment padding
+ ///
+ /// This is the size of the program-significant data in the section,
+ /// exclusive of any alignment padding or reserved or extra space. The
+ /// alignment padding (reserved space) is not represented explicitly, but
+ /// is only implied by the offset of any subsequent non-empty section, or
+ /// in the case of the final section in the image, the image size.
+ ///
+ /// Regardless of the \a iv_offset, if the \a iv_size of a section is 0 it
+ /// should be considered "not present" in the image. In normalized images
+ /// the section offset will always be 0 if the section size is also 0.
+ uint32_t iv_size;
+
+ /// The required initial alignment for the section offset
+ ///
+ /// The image and the applications using P9-XIP images have strict
+ /// alignment/padding requirements. The image does not handle any type of
+ /// unaligned instruction or data fetches. Some sections and subsections
+ /// must also be POWER cache-line aligned. The \a iv_alignment applies to
+ /// the first byte of the section. image images are also required to be
+ /// multiples of 8 bytes in length, to gaurantee that the something will be
+ /// able to complete any 8-byte load/store. These constraints are checked
+ /// by p9_xip_validate() and enforced by p9_xip_append(). The alignment
+ /// constraints may force a section to be padded, which may create "holes"
+ /// in the image as explained in the comments for the \a iv_size field.
+ ///
+ /// Note that alignment constraints are always checked relative to the
+ /// first byte of the image for in-memory images, not relative to the host
+ /// address. Alignment specifications are required to be a power-of-2.
+ uint8_t iv_alignment;
+
+ /// Reserved structure alignment padding; Pad to 12 bytes
+ uint8_t iv_reserved8[3];
+
+} P9XipSection;
+
+/// The P9XipSection structure is created by assembler code and is expected
+/// to have the same size in C code. This constraint is checked in
+/// p9_xip_validate().
+#define SIZE_OF_P9_XIP_SECTION 12
+
+
+/// P9-XIP binary image header
+///
+/// This header occupies the initial bytes of a P9-XIP binary image.
+/// The header contents are documented here, however the structure is actually
+/// defined in the file p9_xip_header.S, and these two definitions must be
+/// kept consistent.
+///
+/// The header is a fixed-format representation of the most critical
+/// information about the image. The large majority of information about the
+/// image and its contents are available through the searchable table of
+/// contents. image code itself normally accesses the data directly through
+/// global symbols.
+///
+/// The header only contains information 1) required by OTPROM code (e.g., the
+/// entry point); 2) required by search and updating APIs (e.g., the
+/// locations and sizes of all of the sections.); a few pieces of critical
+/// meta-data (e.g., information about the image build process).
+///
+/// Any entries that are accessed by image code are required to be 64 bits, and
+/// will appear at the beginning of the header.
+///
+/// The header also contains bytewise offsets and sizes of all of the sections
+/// that are assembled to complete the image. The offsets are relative to the
+/// start of the image (where the header is loaded). The sizes include any
+/// padding inserted by the link editor to guarantee section alignment.
+///
+/// Every field of the header is also accesssible through the searchable table
+/// of contents as documented in p9_xip_header.S.
+
+// -*- DO NOT REORDER OR EDIT THIS STRUCTURE DEFINITION WITHOUT ALSO -*-
+// -*- EDITING THE ASSEMBLER LAYOUT IN p9_xip_header.S, AND WITHOUT -*-
+// -*- UPDATING THE p9_xip_translate_header() API IN p9_xip_image.c. -*-
+
+typedef struct
+{
+
+ //////////////////////////////////////////////////////////////////////
+ // Identification - 8-byte aligned; 8 entries
+ //////////////////////////////////////////////////////////////////////
+
+ /// Contains P9_XIP_MAGIC to identify a P9-XIP image
+ uint64_t iv_magic;
+
+ /// The entry address of the L1 loader entry point in SEEPROM
+ uint64_t iv_L1LoaderAddr;
+
+ /// The entry address of the L2 loader entry point in SRAM
+ uint64_t iv_L2LoaderAddr;
+
+ /// The entry address of Kernel in SRAM
+ uint64_t iv_kernelAddr;
+
+ /// The base address used to link the image, as a full relocatable image
+ /// address
+ uint64_t iv_linkAddress;
+
+ /// Reserved for future expansion
+ uint64_t iv_reserved64[3];
+
+ //////////////////////////////////////////////////////////////////////
+ // Section Table - 4-byte aligned; 16 entries
+ //////////////////////////////////////////////////////////////////////
+
+ P9XipSection iv_section[P9_XIP_SECTIONS];
+
+ //////////////////////////////////////////////////////////////////////
+ // Other information - 4-byte aligned; 8 entries
+ //////////////////////////////////////////////////////////////////////
+
+ /// The size of the image (including padding) in bytes
+ uint32_t iv_imageSize;
+
+ /// Build date generated by `date +%Y%m%d`, e.g., 20110630
+ uint32_t iv_buildDate;
+
+ /// Build time generated by `date +%H%M`, e.g., 0756
+ uint32_t iv_buildTime;
+
+ /// Reserved for future expansion
+ uint32_t iv_reserved32[5];
+
+ //////////////////////////////////////////////////////////////////////
+ // Other Information - 1-byte aligned; 8 entries
+ //////////////////////////////////////////////////////////////////////
+
+ /// Header format version number
+ uint8_t iv_headerVersion;
+
+ /// Indicates whether the image has been normalized (0/1)
+ uint8_t iv_normalized;
+
+ /// Indicates whether the TOC has been sorted to speed searching (0/1)
+ uint8_t iv_tocSorted;
+
+ /// Reserved for future expansion
+ uint8_t iv_reserved8[5];
+
+ //////////////////////////////////////////////////////////////////////
+ // Strings; 64 characters allocated
+ //////////////////////////////////////////////////////////////////////
+
+ /// Build user, generated by `id -un`
+ char iv_buildUser[16];
+
+ /// Build host, generated by `hostname`
+ char iv_buildHost[40];
+
+ /// Reserved for future expansion
+ char iv_reservedChar[8];
+
+} P9XipHeader;
+
+
+
+/// A C-structure form of the P9-XIP Table of Contents (TOC) entries
+///
+/// The .toc section consists entirely of an array of these structures.
+/// TOC entries are never accessed by image code.
+///
+/// These structures store indexing information for global data required to be
+/// manipulated by external tools. The actual data is usually allocated in a
+/// data section and manipulated by the SBE code using global or local symbol
+/// names. Each TOC entry contains a pointer to a keyword string naming the
+/// data, the address of the data (or the data itself), the data type,
+/// meta-information about the data, and for vectors the vector size.
+
+// -*- DO NOT REORDER OR EDIT THIS STRUCTURE DEFINITION WITHOUT ALSO -*-
+// -*- EDITING THE ASSEMBLER MACROS (BELOW) THAT CREATE THE TABLE OF -*-
+// -*- CONTENTS ENTRIES. -*-
+
+typedef struct
+{
+
+ /// A pointer to a 0-byte terminated ASCII string identifying the data.
+ ///
+ /// When allocated by the .xip_toc macro this is a pointer to the string
+ /// form of the symbol name for the global or local symbol associated with
+ /// the data which is allocated in the .strings section. This pointer is
+ /// not aligned.
+ ///
+ /// When the image is normalized this pointer is replaced by the offset of
+ /// the string in the .strings section.
+ uint32_t iv_id;
+
+ /// A 32-bit pointer locating the data
+ ///
+ /// This field is initially populated by the link editor. For scalar,
+ /// vector and string types this is the final relocated address of the
+ /// first byte of the data. For address types, this is the relocated
+ /// address. When the image is normalized, these addresses are converted
+ /// into the equivalent offsets from the beginning of the section holding
+ /// the data.
+ uint32_t iv_data;
+
+ /// The type of the data; See \ref p9_xip_toc_types.
+ uint8_t iv_type;
+
+ /// The section containing the data; See \ref p9_xip_sections.
+ uint8_t iv_section;
+
+ /// The number of elements for vector types, otherwise 1 for scalar types
+ /// and addresses.
+ ///
+ /// Vectors are naturally limited in size, e.g. to the number of cores,
+ /// chips in a node, DD-levels etc. If \a iv_elements is 0 then no bounds
+ /// checking is done on get/set accesses of the data.
+ uint8_t iv_elements;
+
+ /// Structure alignment padding; Pad to 12 bytes
+ uint8_t iv_pad;
+
+} P9XipToc;
+
+/// The P9XipToc structure is created by assembler code and is expected
+/// to have the same size in C code. This constraint is checked in
+/// p9_xip_validate().
+#define SIZE_OF_P9_XIP_TOC 12
+
+
+/// A C-structure form of hashed P9-XIP Table of Contents (TOC) entries
+///
+/// This structure was introduced in order to allow a small TOC for the .fixed
+/// section to support minimum-sized SEEPROM images in which the global TOC
+/// and all strings have been stripped out. In this structure the index
+/// string has been replaced by a 32-bit hash, and there is no longer a record
+/// of the original data name other then the hash. The section of the data is
+/// assumed to be .fixed, with a maximum 16-bit offset.
+///
+/// These structures are created when entries are made in the .fixed section.
+/// They are created empty, then filled in during image normalization.
+///
+/// This structure allows the p9_xip_get*() and p9_xip_set*() APIs to work
+/// even on highly-stripped SEEPROM images.
+
+typedef struct
+{
+
+ /// A 32-bit hash (FNV-1a) of the Id string.
+ uint32_t iv_hash;
+
+ /// The offset in bytes from the start of the (implied) section of the data
+ uint16_t iv_offset;
+
+ /// The type of the data; See \ref p9_xip_toc_types.
+ uint8_t iv_type;
+
+ /// The number of elements for vector types, otherwise 1 for scalar types
+ /// and addresses.
+ ///
+ /// Vectors are naturally limited in size, e.g. to the number of cores,
+ /// chips in a node, DD-levels etc. If \a iv_elements is 0 then no bounds
+ /// checking is done on get/set accesses of the data.
+ uint8_t iv_elements;
+
+} P9XipHashedToc;
+
+/// The P9XipHashedToc structure is created by assembler code and is expected
+/// to have the same size in C code. This constraint is checked in
+/// p9_xip_validate().
+#define SIZE_OF_P9_XIP_HASHED_TOC 8
+
+
+/// A decoded TOC entry for use by applications
+///
+/// This structure is a decoded form of a normalized TOC entry, filled in by
+/// the p9_xip_decode_toc() and p9_xip_find() APIs. This structure is
+/// always returned with data elements in host-endian format.
+///
+/// In the event that the TOC has been removed from the image, this structure
+/// will also be returned by p9_xip_find() with information populated from
+/// the .fixed_toc section if possible. In this case the field \a iv_partial
+/// will be set and only the fields \a iv_address, \a iv_imageData, \a iv_type
+/// and \a iv_elements will be populated (all other fields will be set to 0).
+///
+/// \note Only special-purpose applications will ever need to use this
+/// structure given that the higher-level APIs p9_xip_get_*() and
+/// p9_xip_set_*() are provided and should be used if possible, especially
+/// given that the information may be truncated as described above.
+
+typedef struct
+{
+
+ /// A pointer to the associated TOC entry as it exists in the image
+ ///
+ /// If \a iv_partial is set this field is returned as 0.
+ P9XipToc* iv_toc;
+
+ /// The full relocatable image address
+ ///
+ /// All relocatable addresses are computed from the \a iv_linkAddress
+ /// stored in the header. For scalar and string data, this is the
+ /// relocatable address of the data. For address-only entries, this is
+ /// the indexed address itself.
+ uint64_t iv_address;
+
+ /// A host pointer to the first byte of text or data within the image
+ ///
+ /// For scalar or string types this is a host pointer to the first byte of
+ /// the data. For code pointers (addresses) this is host pointer to the
+ /// first byte of code. Note that any use of this field requires the
+ /// caller to handle conversion of the data to host endian-ness if
+ /// required. Only 8-bit and string data can be used directly on all
+ /// hosts.
+ void* iv_imageData;
+
+ /// The item name
+ ///
+ /// This is a pointer in host memory to a string that names the TOC entry
+ /// requested. This field is set to a pointer to the ID string of the TOC
+ /// entry inside the image. If \a iv_partial is set this field is returned
+ /// as 0.
+ char* iv_id;
+
+ /// The data type, one of the P9_XIP_* constants
+ uint8_t iv_type;
+
+ /// The number of elements in a vector
+ ///
+ /// This field is set from the TOC entry when the TOC entry is
+ /// decoded. This value is stored as 1 for scalar declarations, and may be
+ /// set to 0 for vectors with large or undeclared sizes. Otherwise it is
+ /// used to bounds check indexed accesses.
+ uint8_t iv_elements;
+
+ /// Is this record only partially populated?
+ ///
+ /// This field is set to 0 normally, and only set to 1 if a lookup is made
+ /// in an image that only has the fixed TOC and the requested Id hashes to
+ /// the fixed TOC.
+ uint8_t iv_partial;
+
+} P9XipItem;
+
+
+/// Validate a P9-XIP image
+///
+/// \param[in] i_image A pointer to a P9-XIP image in host memory.
+///
+/// \param[in] i_size The putative size of the image
+///
+/// \param[in] i_maskIgnores Array of ignore bits representing which properties
+/// should not be checked for in p9_xip_validate2().
+///
+/// This API should be called first by all applications that manipulate
+/// P9-XIP images in host memory. The magic number is validated, and
+/// the image is checked for consistency of the section table and table of
+/// contents. The \a iv_imageSize field of the header must also match the
+/// provided \a i_size parameter. Validation does not modify the image.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_validate(void* i_image, const uint32_t i_size);
+
+int
+p9_xip_validate2(void* i_image, const uint32_t i_size,
+ const uint32_t i_maskIgnores);
+
+
+/// Normalize the P9-XIP image
+///
+/// \param[in] io_image A pointer to a P9-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections.
+///
+/// P9-XIP images must be normalized before any other APIs are allowed to
+/// operate on the image. Since normalization modifies the image, an explicit
+/// call to normalize the image is required. Briefly, normalization modifies
+/// the TOC entries created by the final link to simplify search, updates,
+/// modification and relocation of the image. Normalization is explained in
+/// the written documentation of the P9-XIP binary format. Normalization does
+/// not modify the size of the image.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_normalize(void* io_image);
+
+
+/// Return the size of a P9-XIP image from the image header
+///
+/// \param[in] i_image A pointer to a P9-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections.
+///
+/// \param[out] o_size A pointer to a variable returned as the size of the
+/// image in bytes, as recorded in the image header.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_image_size(void* i_image, uint32_t* o_size);
+
+
+/// Locate a section table entry and translate into host format
+///
+/// \param[in] i_image A pointer to a P9-XIP image in host memory.
+///
+/// \param[in] i_sectionId Identifies the section to be queried. See \ref
+/// p9_xip_sections.
+///
+/// \param[out] o_hostSection Updated to contain the section table entry
+/// translated to host byte order.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_get_section(const void* i_image,
+ const int i_sectionId,
+ P9XipSection* o_hostSection);
+
+
+/// Endian translation of a P9XipHeader object
+///
+/// \param[out] o_hostHeader The destination object.
+///
+/// \param[in] i_imageHeader The source object.
+///
+/// Translation of a P9XipHeader includes translation of all data members
+/// including traslation of the embedded section table. This translation
+/// works even if \a o_src == \a o_dest, i.e., in the destructive case.
+void
+p9_xip_translate_header(P9XipHeader* o_hostHeader,
+ const P9XipHeader* i_imageHeader);
+
+
+/// Get scalar data from a P9-XIP image
+///
+/// \param[in] i_image A pointer to a P9-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections. The image is
+/// also required to have been normalized.
+///
+/// \param[in] i_id A pointer to a 0-terminated ASCII string naming the item
+/// requested.
+///
+/// \param[out] o_data A pointer to an 8-byte integer to receive the scalar
+/// data. Assuming the item is located this variable is assigned by the call.
+/// In the event of an error the final state of \a o_data is not specified.
+///
+/// This API searches the P9-XIP Table of Contents (TOC) for the item named
+/// \a i_id, assigning \a o_data from the image if the item is found and is a
+/// scalar value. Scalar values include 8- 32- and 64-bit integers and image
+/// addresses. Image data smaller than 64 bits are extracted as unsigned
+/// types, and it is the caller's responsibility to cast or convert the
+/// returned data as appropriate.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_get_scalar(void* i_image, const char* i_id, uint64_t* o_data);
+
+
+/// Get endianness converted value from the P9-XIP image toc data
+///
+/// \param[in] i_item - decoded toc entry
+
+/// \param[out] o_data A pointer to an 8-byte integer to receive the scalar
+/// data. Assuming the item is located this variable is assigned by the call.
+/// In the event of an error the final state of \a o_data is not specified.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_get_item(const P9XipItem *i_item, uint64_t* o_data);
+
+
+/// Get an integral element from a vector held in a P9-XIP image
+///
+/// \param[in] i_image A pointer to a P9-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections. The image is
+/// also required to have been normalized.
+///
+/// \param[in] i_id A pointer to a 0-terminated ASCII string naming the item
+/// requested.
+///
+/// \param[in] i_index The index of the vector element to return.
+///
+/// \param[out] o_data A pointer to an 8-byte integer to receive the
+/// data. Assuming the item is located this variable is assigned by the call.
+/// In the event of an error the final state of \a o_data is not specified.
+///
+/// This API searches the P9-XIP Table of Contents (TOC) for the \a i_index
+/// element of the item named \a i_id, assigning \a o_data from the image if
+/// the item is found, is a vector of an integral type, and the \a i_index is
+/// in bounds. Vector elements smaller than 64 bits are extracted as unsigned
+/// types, and it is the caller's responsibility to cast or convert the
+/// returned data as appropriate.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_get_element(void* i_image,
+ const char* i_id,
+ const uint32_t i_index,
+ uint64_t* o_data);
+
+
+/// Get string data from a P9-XIP image
+///
+/// \param[in] i_image A pointer to a P9-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections. The image is
+/// also required to have been normalized.
+///
+/// \param[in] i_id A pointer to a 0-terminated ASCII string naming the item
+/// requested.
+///
+/// \param[out] o_data A pointer to a character pointer. Assuming the
+/// item is located this variable is assigned by the call to point to the
+/// string as it exists in the \a i_image. In the event of an error the final
+/// state of \a o_data is not specified.
+///
+/// This API searches the P9-XIP Table of Contents (TOC) for the item named
+/// \a i_id, assigning \a o_data if the item is found and is a string. It is
+/// the caller's responsibility to copy the string from the \a i_image memory
+/// space if necessary.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_get_string(void* i_image, const char* i_id, char** o_data);
+
+
+/// Directly read 64-bit data from the image based on a image address
+///
+/// \param[in] i_image A pointer to a P9-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections.
+///
+/// \param[in] i_imageAddress A relocatable IMAGE address contained in the
+/// image, presumably of an 8-byte data area. The \a i_imageAddress is
+/// required to be 8-byte aligned, otherwise the P9_XIP_ALIGNMENT_ERROR code
+/// is returned.
+///
+/// \param[out] o_data The 64 bit data in host format that was found at \a
+/// i_imageAddress.
+///
+/// This API is provided for applications that need to manipulate P9-XIP
+/// images in terms of their relocatable IMAGE addresses. The API checks that
+/// the \a i_imageAddress is properly aligned and contained in the image, then
+/// reads the contents of \a i_imageAddress into \a o_data, performing
+/// image-to-host endianess conversion if required.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_read_uint64(const void* i_image,
+ const uint64_t i_imageAddress,
+ uint64_t* o_data);
+
+
+/// Set scalar data in a P9-XIP image
+///
+/// \param[in,out] io_image A pointer to a P9-XIP image in host memory.
+/// The image is assumed to be consistent with the information contained in
+/// the header regarding the presence of and sizes of all sections. The image
+/// is also required to have been normalized.
+///
+/// \param[in] i_id A pointer to a 0-terminated ASCII string naming the item
+/// to be modified.
+///
+/// \param[in] i_data The new scalar data.
+///
+/// This API searches the P9-XIP Table of Contents (TOC) for the item named
+/// by \a i_id, updating the image from \a i_data if the item is found, has
+/// a scalar type and can be modified. For this API the scalar types include
+/// 8- 32- and 64-bit integers. Although IMAGE addresses are considered a
+/// scalar type for p9_xip_get_scalar(), IMAGE addresses can not be modified
+/// by this API. The caller is responsible for ensuring that the \a i_data is
+/// of the correct size for the underlying data element in the image.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_set_scalar(void* io_image, const char* i_id, const uint64_t i_data);
+
+
+/// Set an integral element in a vector held in a P9-XIP image
+///
+/// \param[in] i_image A pointer to a P9-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections. The image is
+/// also required to have been normalized.
+///
+/// \param[in] i_id A pointer to a 0-terminated ASCII string naming the item
+/// to be updated.
+///
+/// \param[in] i_index The index of the vector element to update.
+///
+/// \param[out] i_data The new vector element.
+///
+/// This API searches the P9-XIP Table of Contents (TOC) for the \a i_index
+/// element of the item named \a i_id, update the image from \a i_data if the
+/// item is found, is a vector of an integral type, and the \a i_index is in
+/// bounds. The caller is responsible for ensuring that the \a i_data is of
+/// the correct size for the underlying data element in the image.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_set_element(void* i_image,
+ const char* i_id,
+ const uint32_t i_index,
+ const uint64_t i_data);
+
+
+/// Set string data in a P9-XIP image
+///
+/// \param[in,out] io_image A pointer to a P9-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections. The image is
+/// also required to have been normalized.
+///
+/// \param[in] i_id A pointer to a 0-terminated ASCII string naming the item
+/// to be modified.
+///
+/// \param[in] i_data A pointer to the new string data.
+///
+/// This API searches the P9-XIP Table of Contents (TOC) for the item named
+/// \a i_id, which must be a string variable. If found, then the string data
+/// in the image is overwritten with \a i_data. Strings are held 0-terminated
+/// in the image, and the P9-XIP format does not maintain a record of the
+/// amount of memory allocated for an individual string. If a string is
+/// overwritten by a shorter string then the 'excess' storage is effectively
+/// lost. If the length of \a i_data is longer that the current strlen() of
+/// the string data then \a i_data is silently truncated to the first
+/// strlen(old_string) characters.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_set_string(void* io_image, const char* i_id, const char* i_data);
+
+
+/// Directly write 64-bit data into the image based on a IMAGE address
+///
+/// \param[in, out] io_image A pointer to a P9-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections.
+///
+/// \param[in] i_imageAddress A relocatable IMAGE address contained in the
+/// image, presumably of an 8-byte data area. The \a i_imageAddress is
+/// required to be 8-byte aligned, otherwise the P9_XIP_ALIGNMENT_ERROR code
+/// is returned.
+///
+/// \param[in] i_data The 64 bit data in host format to be written to \a
+/// i_imageAddress.
+///
+/// This API is provided for applications that need to manipulate P9-XIP
+/// images in terms of their relocatable IMAGE addresses. The API checks that
+/// the \a i_imageAddress is properly aligned and contained in the image, then
+/// updates the contents of \a i_imageAddress with \a i_data, performing
+/// host-to-image endianess conversion if required.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_write_uint64(void* io_image,
+ const uint64_t i_imageAddress,
+ const uint64_t i_data);
+
+
+/// Map over a P9-XIP image Table of Contents
+///
+/// \param[in,out] io_image A pointer to a P9-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections. The image is
+/// also required to have been normalized.
+///
+/// \param[in] i_fn A pointer to a function to call on each TOC entry. The
+/// function has the prototype:
+///
+/// \code
+/// int (*i_fn)(void* io_image,
+/// const P9XipItem* i_item,
+/// void* io_arg)
+/// \endcode
+///
+/// \param[in,out] io_arg The private argument of \a i_fn.
+///
+/// This API iterates over each entry of the TOC, calling \a i_fn with
+/// pointers to the image, a P9XipItem* pointer, and a private argument. The
+/// iteration terminates either when all TOC entries have been mapped, or \a
+/// i_fn returns a non-zero code.
+///
+/// \retval 0 Success; All TOC entries were mapped, including the case that
+/// the .toc section is empty.
+///
+/// \retval non-0 May be either one of the P9-XIP image error codes (see \ref
+/// p9_xip_image_errors), or a non-zero code from \a i_fn. Since the standard
+/// P9_XIP return codes are > 0, application-defined codes should be < 0.
+int
+p9_xip_map_toc(void* io_image,
+ int (*i_fn)(void* io_image,
+ const P9XipItem* i_item,
+ void* io_arg),
+ void* io_arg);
+
+
+/// Find a P9-XIP TOC entry
+///
+/// \param[in] i_image A pointer to a P9-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections. The image is
+/// also required to have been normalized.
+///
+/// \param[in] i_id A 0-byte terminated ASCII string naming the item to be
+/// searched for.
+///
+/// \param[out] o_item If the search is successful, then the object
+/// pointed to by \a o_item is filled in with the decoded form of the
+/// TOC entry for \a i_id. If the API returns a non-0 error code then the
+/// final state of the storage at \a o_item is undefined. This parameter may
+/// be suppied as 0, in which case p9_xip_find() serves as a simple predicate
+/// on whether an item is indexded in the TOC.
+///
+/// This API searches the TOC of a normalized P9-XIP image for the item named
+/// \a i_id, and if found, fills in the structure pointed to by \a
+/// o_item with a decoded form of the TOC entry. If the item is not found,
+/// the following two return codes may be considered non-error codes:
+///
+/// - P9_XIP_ITEM_NOT_FOUND : No TOC record for \a i_id was found.
+///
+/// - P9_XIP_DATA_NOT_PRESENT : The item appears in the TOC, however the
+/// section containing the data is no longer present in the image.
+///
+/// If the TOC section has been deleted from the image, then the search is
+/// restricted to the abbreviated TOC that indexes data in the .fixed section.
+/// In this case the \a o_item structure is marked with a 1 in the \a
+/// iv_partial field since the abbreviated TOC can not populate the entire
+/// P9XipItem structure.
+///
+/// \note This API should typically only be used as a predicate, not as a way
+/// to access the image via the returned P9XipItem structure. To obtain data
+/// from the image or update data in the image use the p9_xip_get_*() and
+/// p9_xip_set_*() APIs respectively.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_find(void* i_image,
+ const char* i_id,
+ P9XipItem* o_item);
+
+
+
+/// Delete any section, except .header, from a P9-XIP image in host memory,
+/// even in-between sections, i.e. non-final sections.
+///
+/// \param[in,out] io_image A pointer to a P9-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections. The image is
+/// also required to have been normalized. In case of failure in this
+/// funtion, the io_image will get restored to its input value.
+///
+/// \param[out] o_imageBuf A pointer to a pre-allocated buffer that MUST
+/// BE greater than or equal to the size of the \a io_image. The size of
+/// this buffer must be supplied in \a i_imageBufSize. If \a o_imageBuf
+/// is NULL, the supplied \a i_sectionId must be the final section in the
+/// image or this function will fail at deleting the section. On return
+/// from this function, o_imageBuf contains a copy of the initial input
+/// image \a io_image, but only if it's a valid buffer.
+///
+/// \param[in] i_imageBufSize The size of \a o_imageBuf buffer. It MUST
+/// BE greater than or equal to the size of \a io_image. However, if \a
+/// o_imageBuf is NULL, then this arg is ignored.
+///
+/// \param[in] i_sectionId Identifies the section to be deleted. See \ref
+/// p9_xip_sections.
+///
+/// This API effectively deletes a section from a P9-XIP image held in host
+/// memory. Deleting a section of the image means that the section size is
+/// set to 0, and the size of the image recorded in the header is reduced by
+/// the section size. Any alignment padding of the in-between section is
+/// also handled, i.e. removed if final section and re-applied upon
+/// re-appending sections. In the special case where \a o_imageBuf is
+/// NULL, unless the requested \a i_sectionId is already empty, only the final
+/// section (highest address offset) of the image may be deleted.
+///
+/// \note This API does not check for or warn if other sections in the image
+/// reference the deleted section.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_delete_section(void* io_image,
+ void* o_imageBuf,
+ const uint32_t i_imageBufSize,
+ const int i_sectionId);
+
+
+
+#ifndef PPC_HYP
+
+/// Duplicate a section from a P9-XIP image in host memory
+///
+/// \param[in,out] i_image A pointer to a P9-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections.
+///
+/// \param[in] i_sectionId Identifies the section to be duplicated. See \ref
+/// p9_xip_sections.
+///
+/// \param[out] o_duplicate At exit, points to the newly allocated and
+/// initialized duplicate of the given section. The caller is responsible for
+/// free()-ing this memory when no longer required.
+///
+/// \param[out] o_size At exit, contains the size (in bytes) of the duplicated
+/// section.
+///
+/// This API creates a bytewise duplicate of a non-empty section into newly
+/// malloc()-ed memory. At exit \a o_duplicate points to the duplicate, and \a
+/// o_size is set the the size of the duplicated section. The caller is
+/// responsible for free()-ing the memory when no longer required. The
+/// pointer at \a o_duplicate is set to NULL (0) and the \a o_size is set to 0
+/// in the event of any failure.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_duplicate_section(const void* i_image,
+ const int i_sectionId,
+ void** o_duplicate,
+ uint32_t* o_size);
+
+#endif // PPC_HYP
+
+
+/// Append binary data to a P9-XIP image held in host memory
+///
+/// \param[in,out] io_image A pointer to a P9-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections. The image is
+/// also required to have been normalized.
+///
+/// \param[in] i_sectionId Identifies the section to contain the new data.
+///
+/// \param[in] i_data A pointer to the data to be appended to the image. If
+/// this pointer is NULL (0), then the effect is as if \a i_data were a
+/// pointer to an \a i_size array of 0 bytes.
+///
+/// \param[in] i_size The size of the data to be appended in bytes. If \a
+/// i_data is 0, then this is the number of bytes to clear.
+///
+/// \param[in] i_allocation The size of the memory region containing the
+/// image, measured from the first byte of the image. The call will fail if
+/// appending the new data plus any alignment padding would overflow the
+/// allocated memory.
+///
+/// \param[out] o_sectionOffset If non-0 at entry, then the API updates the
+/// location pointed to by \a o_sectionOffset with the offset of the first
+/// byte of the appended data within the indicated section. This return value
+/// is invalid in the event of a non-0 return code.
+///
+/// This API copies data from \a i_data to the end of the indicated \a
+/// i_section. The section \a i_section must either be empty, or must be the
+/// final (highest address) section in the image. If the section is initially
+/// empty and \a i_size is non-0 then the section is created at the end of the
+/// image. The size of \a i_section and the size of the image are always
+/// adjusted to reflect the newly added data. This is a simple binary copy
+/// without any interpretation (e.g., endian-translation) of the copied data.
+/// The caller is responsible for insuring that the host memory area
+/// containing the P9-XIP image is large enough to hold the newly appended
+/// data without causing addressing errors or buffer overrun errors.
+///
+/// The final parameter \a o_sectionOffset is optional, and may be passed as
+/// NULL (0) if the application does not require the information. This return
+/// value is provided to simplify typical use cases of this API:
+///
+/// - A scan program is appended to the image, or a run-time data area is
+/// allocated and cleared at the end of the image.
+///
+/// - Pointer variables in the image are updated with IMAGE addresses obtained
+/// via p9_xip_section2image(), or
+/// other procedure code initializes a newly allocated and cleared data area
+/// via host addresses obtained from p9_xip_section2host().
+///
+/// Regarding alignment, note that the P9-XIP format requires that sections
+/// maintain an initial alignment that varies by section, and the API will
+/// enforce these alignment constraints for all sections created by the API.
+/// All alignment is relative to the first byte of the image (\a io_image) -
+/// \e not to the current in-memory address of the image. By specification
+/// P9-XIP images must be loaded at a 4K alignment in order for IMAGE hardware
+/// relocation to work, however the APIs don't require this 4K alignment for
+/// in-memory manipulation of images. Images to be executed on ImageVe will
+/// normally require at least 8-byte final aligment in order to guarantee that
+/// the ImageVe can execute an 8-byte fetch or load/store of the final
+/// doubleword.
+///
+/// \note If the TOC section is modified then the image is marked as having an
+/// unsorted TOC.
+///
+/// \note If the call fails for any reason (other than a bug in the API
+/// itself) then the \a io_image data is returned unmodified.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_append(void* io_image,
+ const int i_sectionId,
+ const void* i_data,
+ const uint32_t i_size,
+ const uint32_t i_allocation,
+ uint32_t* o_sectionOffset);
+
+
+/// Convert a P9-XIP section offset to a relocatable IMAGE address
+///
+/// \param[in] i_image A pointer to a P9-XIP image in host memory
+///
+/// \param[in] i_sectionId A valid P9-XIP section identifier; The section
+/// must be non-empty.
+///
+/// \param[in] i_offset An offset (in bytes) within the section. At least one
+/// byte at \a i_offset must be currently allocated in the section.
+///
+/// \param[in] o_imageAddress The equivalent relocatable IMAGE address is
+/// returned via this pointer. Since valid IMAGE addresses are always either
+/// 4-byte (code) or 8-byte (data) aligned, this API checks the aligment of
+/// the translated address and returns P9_XIP_ALIGNMENT_ERROR if the IMAGE
+/// address is not at least 4-byte aligned. Note that the translated address
+/// is still returned even if incorrectly aligned.
+///
+/// This API is typically used to translate section offsets returned from
+/// p9_xip_append() into relocatable IMAGE addresses.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_section2image(const void* i_image,
+ const int i_sectionId,
+ const uint32_t i_offset,
+ uint64_t* o_imageAddress);
+
+
+/// Convert a P9-XIP relocatable image address to a host memory address
+///
+/// \param[in] i_image A pointer to a P9-XIP image in host memory.
+///
+/// \param[in] i_imageAddress A relocatable image address putatively addressing
+/// relocatable memory contained in the image.
+///
+/// \param[out] o_hostAddress The API updates the location pointed to by \a
+/// o_hostAddress with the host address of the memory addressed by \a
+/// i_imageAddress. In the event of an error (non-0 return code) the final
+/// content of \a o_hostAddress is undefined.
+///
+/// This API is typically used to translate relocatable image addresses stored
+/// in the P9-XIP image into the equivalent host address of the in-memory
+/// image, allowing host-code to manipulate arbitrary data structures in the
+/// image. If the \a i_imageAddress does not refer to memory within the image
+/// (as determined by the link address and image size) then the
+/// P9_XIP_INVALID_ARGUMENT error code is returned.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_image2host(const void* i_image,
+ const uint64_t i_imageAddress,
+ void** o_hostAddress);
+
+
+/// Convert a P9-XIP relocatable image address to section Id and offset
+///
+/// \param[in] i_image A pointer to a P9-XIP image in host memory.
+///
+/// \param[in] i_imageAddress A relocatable image address putatively addressing
+/// relocatable memory contained in the image.
+///
+/// \param[out] o_section The API updates the location pointed to by \a
+/// o_section with the section Id of the memory addressed by \a
+/// i_imageAddress. In the event of an error (non-0 return code) the final
+/// content of \a o_section is undefined.
+///
+/// \param[out] o_offset The API updates the location pointed to by \a
+/// o_offset with the byte offset of the memory addressed by \a i_imageAddress
+/// within \a o_section. In the event of an error (non-0 return code) the
+/// final content of \a o_offset is undefined.
+///
+/// This API is typically used to translate relocatable image addresses stored
+/// in the P9-XIP image into the equivalent section + offset form, allowing
+/// host-code to manipulate arbitrary data structures in the image. If the \a
+/// i_imageAddress does not refer to memory within the image (as determined by
+/// the link address and image size) then the P9_XIP_INVALID_ARGUMENT error
+/// code is returned.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_image2section(const void* i_image,
+ const uint64_t i_imageAddress,
+ int* o_section,
+ uint32_t* o_offset);
+
+
+/// Convert an in-memory P9-XIP host address to a relocatable image address
+///
+/// \param[in] i_image A pointer to a P9-XIP image in host memory
+///
+/// \param[in] i_hostAddress A host address addressing data within the image.
+///
+/// \param[out] o_imageAddress The API updates the location pointed to by \a
+/// o_imageAddress with the equivelent relocatable image address of the memory
+/// addressed by i_hostAddress. Since valid image addresses are always either
+/// 4-byte (code) or 8-byte (data) aligned, this API checks the aligment of
+/// the translated address and returns P9_XIP_ALIGNMENT_ERROR if the image
+/// address is not at least 4-byte aligned. Note that the translated address
+/// is still returned evn if incorrectly aligned.
+///
+/// This API is provided as a convenient way to convert host memory addresses
+/// for an in-memory P9-XIP image into image addresses correctly relocated for
+/// the image, for example to update pointer variables in the image. If the
+/// \a i_hostAddress does not refer to memory within the image (as determined
+/// by the image address and image size) then the P9_XIP_INVALID_ARGUMENT
+/// error code is returned.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_host2image(const void* i_image,
+ void* i_hostAddress,
+ uint64_t* o_imageAddress);
+
+/// Get all the information required to search and find the TOC
+///
+/// \param[in] i_image A pointer to a P9-XIP image in host memory
+///
+/// \param[out][optional] o_toc A pointer to TOC listing
+///
+/// \param[out][optional] o_entries Number of TOC entries located
+///
+/// \param[out][optional] o_sorted Indication if the TOC is sorted
+///
+/// \param[out][optional] o_strings A pointer to String section containing TOC
+/// names
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref p9_xip_image_errors
+int
+p9_xip_get_toc(void* i_image,
+ P9XipToc** o_toc,
+ size_t* o_entries,
+ int* o_sorted,
+ char** o_strings);
+
+
+/// \brief Decode a TOC entry from dump file
+///
+///\param[in] - i_image - seeprom image
+///\param[in] - i_dump - dump file
+///\param[in] - i_imageToc - TOC entry
+///\param[out] - o_item - decoded toc entry
+///
+///\return - 0 Success; non-0 See \ref p9_xip_image_errors
+int
+p9_xip_decode_toc_dump(void* i_image, void* i_dump,
+ P9XipToc* i_imageToc,
+ P9XipItem* o_item);
+
+// PHYP has their own way of implementing the <string.h> functions. PHYP also
+// does not allow static functions or data, so all of the XIP_STATIC functions
+// defined here are global to PHYP.
+
+#ifdef PPC_HYP
+
+ #ifdef PLIC_MODULE
+ #define strcpy(dest, src) hvstrcpy(dest, src)
+ #define strlen(s) hvstrlen(s)
+ #define strcmp(s1, s2) hvstrcmp(s1, s2)
+ #endif //PLIC_MODULE
+
+ #define XIP_STATIC
+
+#else // PPC_HYP
+
+ // #define XIP_STATIC static
+ #define XIP_STATIC
+
+#endif // PPC_HYP
+
+/// \defgroup p9_xip_image_errors Error codes from P9-XIP image APIs
+///
+/// @{
+
+/// A putative P9-XIP image does not have the correct magic number, or
+/// contains some other major inconsistency.
+#define P9_XIP_IMAGE_ERROR 1
+
+/// The TOC may be missing, partially present or may have an alignment problem.
+#define P9_XIP_TOC_ERROR 2
+
+/// A named item was not found in the P9-XIP TOC, or a putative HALT address
+/// is not associated with a halt code in .halt.
+#define P9_XIP_ITEM_NOT_FOUND 3
+
+/// A named item appears in the P9-XIP TOC, but the data is not present in
+/// the image. This error can occur if sections have been deleted from the
+/// image.
+#define P9_XIP_DATA_NOT_PRESENT 4
+
+/// A named item appears in the P9-XIP TOC, but the data can not be
+/// modified. This error will occur if an attempt is made to modify an
+/// address-only entry.
+#define P9_XIP_CANT_MODIFY 5
+
+/// A direct or implied argument is invalid, e.g. an illegal data type or
+/// section identifier, or an address not contained within the image.
+#define P9_XIP_INVALID_ARGUMENT 6
+
+/// A data type mismatch or an illegal type was specified or implied for an
+/// operation.
+#define P9_XIP_TYPE_ERROR 7
+
+/// A bug in a P9-XIP image API
+#define P9_XIP_BUG 8
+
+/// The image must first be normalized with p9_xip_normalize().
+#define P9_XIP_NOT_NORMALIZED 9
+
+/// Attempt to delete a non-empty section that is not the final section of the
+/// image, or an attempt to append data to a non-empty section that is not the
+/// final section of the image, or an attempt to operate on an empty section
+/// for those APIs that prohibit this.
+#define P9_XIP_SECTION_ERROR 10
+
+/// An address translation API returned a image address that was not at least
+/// 4-byte aligned, or alignment violations were observed by
+/// p9_xip_validate() or p9_xip_append().
+#define P9_XIP_ALIGNMENT_ERROR 11
+
+/// An API that performs dynamic memory allocation was unable to allocate
+/// memory.
+#define P9_XIP_NO_MEMORY 12
+
+/// Attempt to get or set a vector element with an index that is outside of
+/// the declared bounds of the vector.
+#define P9_XIP_BOUNDS_ERROR 13
+
+/// Attempt to grow the image past its defined memory allocation
+#define P9_XIP_WOULD_OVERFLOW 14
+
+/// Error associated with the disassembler occured.
+#define P9_XIP_DISASSEMBLER_ERROR 15
+
+/// Hash collision creating the .fixed_toc section
+#define P9_XIP_HASH_COLLISION 16
+
+/// Invalid buffer. It had a NULL ptr.
+#define P9_XIP_NULL_BUFFER 17
+
+/// Image has been broken and unable to restore original image.
+#define P9_XIP_CANT_RESTORE_IMAGE 18
+
+/// Applications can expand this macro to declare an array of string forms of
+/// the error codes if desired.
+#define P9_XIP_ERROR_STRINGS(var) \
+ const char* var[] = { \
+ "Success", \
+ "P9_XIP_IMAGE_ERROR", \
+ "P9_XIP_TOC_ERROR", \
+ "P9_XIP_ITEM_NOT_FOUND", \
+ "P9_XIP_DATA_NOT_PRESENT", \
+ "P9_XIP_CANT_MODIFY", \
+ "P9_XIP_INVALID_ARGUMENT", \
+ "P9_XIP_TYPE_ERROR", \
+ "P9_XIP_BUG", \
+ "P9_XIP_NOT_NORMALIZED", \
+ "P9_XIP_SECTION_ERROR", \
+ "P9_XIP_ALIGNMENT_ERROR", \
+ "P9_XIP_NO_MEMORY", \
+ "P9_XIP_BOUNDS_ERROR", \
+ "P9_XIP_WOULD_OVERFLOW", \
+ "P9_XIP_DISASSEMBLER_ERROR", \
+ "P9_XIP_HASH_COLLISION", \
+ "P9_XIP_NULL_BUFFER", \
+ "P9_XIP_CANT_RESTORE_IMAGE", \
+ }
+
+/// Applications can use this macro to safely index the array of error
+/// strings.
+#define P9_XIP_ERROR_STRING(var, n) \
+ ((((n) < 0) || ((n) > (int)(sizeof(var) / sizeof(char*)))) ? \
+ "Bug : Invalid P9-XIP error code" : var[n])
+
+/// @}
+
+/// Disassembler error codes.
+#define DIS_IMAGE_ERROR 1
+#define DIS_MEMORY_ERROR 2
+#define DIS_DISASM_ERROR 3
+#define DIS_RING_NAME_ADDR_MATCH_SUCCESS 4
+#define DIS_RING_NAME_ADDR_MATCH_FAILURE 5
+#define DIS_TOO_MANY_DISASM_WARNINGS 6
+#define DIS_DISASM_TROUBLES 7
+
+#define DIS_ERROR_STRINGS(var) \
+ const char* var[] = { \
+ "Success", \
+ "DIS_IMAGE_ERROR", \
+ "DIS_MEMORY_ERROR", \
+ "DIS_DISASM_ERROR", \
+ "DIS_RING_NAME_ADDR_MATCH_SUCCESS", \
+ "DIS_RING_NAME_ADDR_MATCH_FAILURE", \
+ "DIS_TOO_MANY_DISASM_WARNINGS", \
+ "DIS_DISASM_TROUBLES", \
+ }
+
+#define DIS_ERROR_STRING(var, n) \
+ ((((n) < 0) || ((n) > (int)(sizeof(var) / sizeof(char*)))) ? \
+ "Bug : Invalid DIS error code" : var[n])
+
+#if 0
+{
+ /* So __cplusplus doesn't mess w/auto-indent */
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __ASSEMBLER__
+
+
+////////////////////////////////////////////////////////////////////////////
+// Assembler Definitions
+////////////////////////////////////////////////////////////////////////////
+
+#ifdef __ASSEMBLER__
+
+/// Create an XIP TOC entry
+///
+/// \param[in] index The string form of the \a index symbol is created and
+/// linked from the TOC entry to allow external search procedures to locate
+/// the \a address.
+///
+/// \param[in] type One of the P9_XIP_* type constants; See \ref
+/// p9_xip_toc_types.
+///
+/// \param[in] address The address of the idexed code or data; This will
+/// typically be a symbol.
+///
+/// \param[in] elements <Optional> For vector types, number of elements in the
+/// vector, which is limited to an 8-bit unsigned integer. This parameter
+/// defaults to 1 which indicates a scalar type. Declaring a vector with 0
+/// elements disables bounds checking on vector accesses, and can be used if
+/// very large or indeterminate sized vectors are required. The TOC format
+/// does not support vectors of strings or addresses.
+///
+/// The \c .xip_toc macro creates a XIP Table of Contents (TOC) structure in
+/// the \c .toc section, as specified by the parameters. This macro is
+/// typically not used directly in assembly code. Instead programmers should
+/// use .xip_quad, .xip_quada, .xip_quadia, .xip_address or .xip_string
+
+ .macro .xip_toc, index:req, type:req, address:req, elements=1
+
+ .if (((\type) < 1) || ((\type) > P9_XIP_MAX_TYPE_INDEX))
+ .error ".xip_toc : Illegal type index"
+ .endif
+
+ // First push into the .strings section to lay down the
+ // string form of the index name under a local label.
+
+ .pushsection .strings
+7667862:
+ .asciz "\index"
+ .popsection
+
+ // Now the 12-byte TOC entry is created. Push into the .toc section
+ // and lay down the first 4 bytes which are always a pointer to the
+ // string just declared. The next 4 bytes are the address of the data
+ // (or the address itself in the case of address types). The final 4
+ // bytes are the type, section (always 0 prior to normalization),
+ // number of elements, and a padding byte.
+
+ .pushsection .toc
+
+ .long 7667862b, (\address)
+ .byte (\type), 0, (\elements), 0
+
+ .popsection
+
+ .endm
+
+
+/// Allocate and initialize 64-bit global scalar or vector data and create the
+/// TOC entry.
+///
+/// \param[in] symbol The name of the scalar or vector; this name is also used
+/// as the TOC index of the data.
+///
+/// \param[in] init The initial value of (each element of) the data.
+/// This is a 64-bit integer; To allocate address pointers use .xip_quada.
+///
+/// \param[in] elements The number of 64-bit elements in the data structure,
+/// defaulting to 1, with a maximum value of 255.
+///
+/// \param[in] section The section where the data will be allocated,
+/// default depends on the memory space
+
+ .macro .xip_quad, symbol:req, init:req, elements=1, section
+
+ ..xip_quad_helper .quad, \symbol, (\init), (\elements), \section
+
+ .endm
+
+
+/// Allocate and initialize 64-bit global scalar or vector data containing a
+/// relocatable address in and create the TOC entry.
+///
+/// \param[in] symbol The name of the scalar or vector; this name is also used
+/// as the TOC index of the data.
+///
+/// \param[in] init The initial value of (each element of) the data. This
+/// will typically be a symbolic address. If the intention is to define an
+/// address that will always be filled in later by image manipulation tools,
+/// then use the .xip_quad macro with a 0 initial value.
+///
+/// \param[in] elements The number of 64-bit elements in the data structure,
+/// defaulting to 1, with a maximum value of 255.
+///
+/// \param[in] section The section where the data will be allocated,
+/// default depends on the memory space
+
+ .macro .xip_quada, symbol:req, offset:req, elements=1, section
+
+ ..xip_quad_helper .quada, \symbol, (\offset), (\elements), \section
+
+ .endm
+
+
+/// Helper for .xip_quad and .xip_quada
+
+ .macro ..xip_quad_helper, directive, symbol, init, elements, section
+
+ .if (((\elements) < 1) || ((\elements) > 255))
+ .error "The number of vector elements must be in the range 1..255"
+ .endif
+
+ ..xip_pushsection \section
+ .balign 8
+
+ .global \symbol
+\symbol\():
+ .rept (\elements)
+ \directive (\init)
+ .endr
+
+ .popsection
+
+ .xip_toc \symbol, P9_XIP_UINT64, \symbol, (\elements)
+
+ .endm
+
+
+/// Allocate and initialize 64-bit global scalar or vector data containing
+/// full 64-bit addresses and create a TOC entry
+///
+/// \param[in] symbol The name of the scalar or vector; this name is also used
+/// as the TOC index of the data.
+///
+/// \param[in] space A valid image memory space descriptor
+///
+/// \param[in] offset A 32-bit relocatable offset
+///
+/// \param[in] elements The number of 64-bit elements in the data structure,
+/// defaulting to 1, with a maximum value of 255.
+///
+/// \param[in] section The section where the data will be allocated,
+/// default depends on the memory space
+
+ .macro .xip_quadia, symbol:req, space:req, offset:req, elements=1, section
+
+ .if (((\elements) < 1) || ((\elements) > 255))
+ .error "The number of vector elements must be in the range 1..255"
+ .endif
+
+ ..xip_pushsection \section
+ .balign 8
+
+ .global \symbol
+\symbol\():
+ .rept (\elements)
+ .quadia (\space), (\offset)
+ .endr
+
+ .popsection
+
+ .xip_toc \symbol, P9_XIP_UINT64, \symbol, (\elements)
+
+ .endm
+
+/// Default push into .ipl_data unless in an OCI space, then .data
+
+ .macro ..xip_pushsection, section
+
+ .ifnb \section
+ .pushsection \section
+ .else
+ .if (_PGAS_DEFAULT_SPACE == PORE_SPACE_OCI)
+ .pushsection .data
+ .else
+ .pushsection .ipl_data
+ .endif
+ .endif
+
+ .balign 8
+
+ .endm
+
+/// Allocate and initialize a string in .strings
+///
+/// \param[in] index The string will be stored in the TOC using this index
+/// symbol.
+///
+/// \param[in] string The string to be allocated in .strings. String space is
+/// fixed once allocated. Strings designed to be overwritten by external tools
+/// should be allocated to be as long as eventually needed (e.g., by a string
+/// of blanks.)
+
+ .macro .xip_string, index:req, string:req
+
+ .pushsection .strings
+7874647:
+ .asciz "\string"
+ .popsection
+
+ .xip_toc \index, P9_XIP_STRING, 7874647b
+
+ .endm
+
+
+/// Shorthand to create a TOC entry for an address
+///
+/// \param[in] index The symbol will be indexed as this name
+///
+/// \param[in] symbol <Optional> The symbol to index; by default the same as
+/// the index.
+
+ .macro .xip_address, index:req, symbol
+
+ .ifb \symbol
+ .xip_toc \index, P9_XIP_ADDRESS, \index
+ .else
+ .xip_toc \index, P9_XIP_ADDRESS, \symbol
+ .endif
+
+ .endm
+
+
+ .macro .xip_section, s, alignment=1, empty=0
+ .ifnb \s
+_\s\()_section:
+ .if \empty
+ .long 0
+ .long 0
+ .else
+ .long _\s\()_offset
+ .long _\s\()_size
+ .endif
+ .else
+ .long 0
+ .long 0
+ .endif
+ .byte (\alignment)
+ .byte 0, 0, 0
+ .endm
+
+#endif // __ASSEMBLER__
+
+#ifndef __ASSEMBLER__
+
+/**************************************************************************/
+/* SBE Image */
+/**************************************************************************/
+
+typedef enum
+{
+ P9_XIP_SECTION_SBE_LOADERTEXT = P9_XIP_SECTIONS_PLUS(0),
+ P9_XIP_SECTION_SBE_LOADERDATA = P9_XIP_SECTIONS_PLUS(1),
+ P9_XIP_SECTION_SBE_TEXT = P9_XIP_SECTIONS_PLUS(2),
+ P9_XIP_SECTION_SBE_DATA = P9_XIP_SECTIONS_PLUS(3),
+ P9_XIP_SECTION_SBE_BASE = P9_XIP_SECTIONS_PLUS(4),
+ P9_XIP_SECTION_SBE_BASELOADER = P9_XIP_SECTIONS_PLUS(5),
+ P9_XIP_SECTION_SBE_OVERRIDES = P9_XIP_SECTIONS_PLUS(6),
+ P9_XIP_SECTION_SBE_RINGS = P9_XIP_SECTIONS_PLUS(7),
+ P9_XIP_SECTION_SBE_OVERLAYS = P9_XIP_SECTIONS_PLUS(8),
+ P9_XIP_SECTION_SBE_HBBL = P9_XIP_SECTIONS_PLUS(9),
+ P9_XIP_SECTIONS_SBE = P9_XIP_SECTIONS_PLUS(10) // # sections
+} p9_xip_section_sbe_t;
+
+#define P9_XIP_SECTION_NAMES_SBE(var) \
+ P9_XIP_SECTION_NAMES(var, \
+ ".loader_text", \
+ ".loader_data", \
+ ".text", \
+ ".data", \
+ ".base", \
+ ".baseloader", \
+ ".overrides", \
+ ".rings", \
+ ".overlays", \
+ ".hbbl")
+
+/**************************************************************************/
+/* Hardware Image */
+/**************************************************************************/
+
+typedef enum
+{
+ P9_XIP_SECTION_HW_SGPE = P9_XIP_SECTIONS_PLUS(0),
+ P9_XIP_SECTION_HW_RESTORE = P9_XIP_SECTIONS_PLUS(1),
+ P9_XIP_SECTION_HW_CME = P9_XIP_SECTIONS_PLUS(2),
+ P9_XIP_SECTION_HW_PGPE = P9_XIP_SECTIONS_PLUS(3),
+ P9_XIP_SECTION_HW_IOPPE = P9_XIP_SECTIONS_PLUS(4),
+ P9_XIP_SECTION_HW_FPPE = P9_XIP_SECTIONS_PLUS(5),
+ P9_XIP_SECTION_HW_RINGS = P9_XIP_SECTIONS_PLUS(6),
+ P9_XIP_SECTIONS_HW = P9_XIP_SECTIONS_PLUS(7) // # sections
+} p9_xip_section_hw_t;
+
+#define P9_XIP_SECTION_NAMES_HW(var) \
+ P9_XIP_SECTION_NAMES(var, \
+ ".sgpe", \
+ ".core_restore", \
+ ".cme", \
+ ".pgpe", \
+ ".ioppe", \
+ ".fppe", \
+ ".rings")
+
+/**************************************************************************/
+/* SGPE Image */
+/**************************************************************************/
+
+typedef enum
+{
+ P9_XIP_SECTION_SGPE_QPMR = P9_XIP_SECTIONS_PLUS(0),
+ P9_XIP_SECTION_SGPE_LVL1_BL = P9_XIP_SECTIONS_PLUS(1),
+ P9_XIP_SECTION_SGPE_LVL2_BL = P9_XIP_SECTIONS_PLUS(2),
+ P9_XIP_SECTION_SGPE_HCODE = P9_XIP_SECTIONS_PLUS(3),
+ P9_XIP_SECTIONS_SGPE = P9_XIP_SECTIONS_PLUS(4) // # sections
+} p9_xip_section_sgpe_t;
+
+#define P9_XIP_SECTION_NAMES_SGPE(var) \
+ P9_XIP_SECTION_NAMES(var, \
+ ".qpmr", \
+ ".lvl1_bl", \
+ ".lvl2_bl", \
+ ".hcode")
+
+/**************************************************************************/
+/* Core Restore Image */
+/**************************************************************************/
+
+typedef enum
+{
+ P9_XIP_SECTION_RESTORE_CPMR = P9_XIP_SECTIONS_PLUS(0),
+ P9_XIP_SECTION_RESTORE_SELF = P9_XIP_SECTIONS_PLUS(1),
+ P9_XIP_SECTIONS_RESTORE = P9_XIP_SECTIONS_PLUS(2) // # sections
+} p9_xip_section_restore_t;
+
+#define P9_XIP_SECTION_NAMES_RESTORE(var) \
+ P9_XIP_SECTION_NAMES(var, \
+ ".cpmr", \
+ ".self_restore")
+
+/**************************************************************************/
+/* CME Image */
+/**************************************************************************/
+
+typedef enum
+{
+ P9_XIP_SECTION_CME_HCODE = P9_XIP_SECTIONS_PLUS(0),
+ P9_XIP_SECTIONS_CME = P9_XIP_SECTIONS_PLUS(1) // # sections
+} p9_xip_section_cme_t;
+
+#define P9_XIP_SECTION_NAMES_CME(var) \
+ P9_XIP_SECTION_NAMES(var, \
+ ".hcode")
+
+/**************************************************************************/
+/* PGPE Image */
+/**************************************************************************/
+
+typedef enum
+{
+ P9_XIP_SECTION_PGPE_LVL1_BL = P9_XIP_SECTIONS_PLUS(0),
+ P9_XIP_SECTION_PGPE_LVL2_BL = P9_XIP_SECTIONS_PLUS(1),
+ P9_XIP_SECTION_PGPE_HCODE = P9_XIP_SECTIONS_PLUS(2),
+ P9_XIP_SECTIONS_PGPE = P9_XIP_SECTIONS_PLUS(3) // # sections
+} p9_xip_section_pgpe_t;
+
+#define P9_XIP_SECTION_NAMES_PGPE(var) \
+ P9_XIP_SECTION_NAMES(var, \
+ ".lvl1_bl", \
+ ".lvl2_bl", \
+ ".hcode")
+
+/**************************************************************************/
+/* IOPPE Image */
+/**************************************************************************/
+
+typedef enum
+{
+ P9_XIP_SECTIONS_IOPPE = P9_XIP_SECTIONS_PLUS(0) // # sections
+} p9_xip_section_ioppe_t;
+
+#define P9_XIP_SECTION_NAMES_IOPPE(var) \
+ P9_XIP_SECTION_NAMES(var)
+
+/**************************************************************************/
+/* FPPE Image */
+/**************************************************************************/
+
+typedef enum
+{
+ P9_XIP_SECTIONS_FPPE = P9_XIP_SECTIONS_PLUS(0) // # sections
+} p9_xip_section_fppe_t;
+
+#define P9_XIP_SECTION_NAMES_FPPE(var) \
+ P9_XIP_SECTION_NAMES(var)
+
+
+#endif /* !__ASSEMBLER__ */
+
+#endif // __P9_XIP_IMAGE_H
+
+// *INDENT-ON*
diff --git a/src/import/chips/p9/xip/p9_xip_tool.C b/src/import/chips/p9/xip/p9_xip_tool.C
new file mode 100644
index 00000000..dd48e250
--- /dev/null
+++ b/src/import/chips/p9/xip/p9_xip_tool.C
@@ -0,0 +1,2594 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: import/chips/p9/xip/p9_xip_tool.C $ */
+/* */
+/* OpenPOWER sbe Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+/// \file p9_xip_tool.c
+/// \brief P9-XIP image search/edit tool
+///
+/// Note: This file was originally stored under .../procedures/ipl/sbe. It
+/// was moved here at version 1.19.
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define __PPE__
+
+#include "p9_xip_image.h"
+#ifdef XIP_TOOL_ENABLE_DISSECT
+ #include "p9_tor.H"
+ #include "p9_scan_compression.H"
+ using namespace P9_TOR;
+#endif
+
+#define LINE_SIZE_MAX 1024 // Max size of a single snprintf dump.
+#define RING_BUF_SIZE_MAX 1000000
+
+// Listing mode IDs:
+//
+enum LISTING_MODE_ID
+{
+ LMID_SHORT = 0,
+ LMID_NORMAL = 1, // default
+ LMID_LONG = 2
+};
+
+// Usage: p9_xip_tool <image> [-<flag> ...] normalize
+// p9_xip_tool <image> [-<flag> ...] get <item>
+// p9_xip_tool <image> [-<flag> ...] getv <item> <index>
+// p9_xip_tool <image> [-<flag> ...] set <item> <value> [ <item1> <value1> ... ]
+// p9_xip_tool <image> [-<flag> ...] setv <item> <index> <value> [ <item1> <index1> <value1> ... ]
+// p9_xip_tool <image> [-<flag> ...] report [<regex>]
+// p9_xip_tool <image> [-<flag> ...] attrdump <attr dump file>
+// p9_xip_tool <image> [-<flag> ...] append <section> <file>
+// p9_xip_tool <image> [-<flag> ...] extract <section> <file>
+// p9_xip_tool <image> [-<flag> ...] delete <section> [ <section1> ... <sectionN> ]
+// p9_xip_tool <image> [-<flag> ...] dissect <ring section> [short,normal(default),long]
+// p9_xip_tool <image> [-<flag> ...] disasm <text section>
+//
+// This simple application uses the P9-XIP image APIs to normalize, search
+// update and edit P9-XIP images. This program encapsulates several commands
+// in a common command framework which requires an image to operate on, a
+// command name, and command arguments that vary by command. Commands that
+// modify the image always rewrite the image in-place in the filesystem;
+// however the original image is only modified if the command has completed
+// without error.
+//
+// The program operates on a P9-XIP format binary image, which must be
+// normalized - unless the tool is being called to normalize the image in the
+// first place using the 'normalize' command. The tool also validates the
+// image prior to operating on the image.
+//
+// The 'get' command retrieves a scalar value from the image and prints its
+// representation on stdout (followed by a newline). Scalar integer values
+// and image addresses are printed as hex numbers (0x...). Strings are printed
+// verbatim.
+//
+// The 'getv' command retrieves a vector element from the image and prints its
+// representation on stdout (followed by a newline). Integer values
+// and image addresses are printed as hex numbers (0x...). Vectors of strings
+// are not supported.
+//
+// The 'set' command allows setting integer and string values in the image.
+// New integer values can be specified in decimal or hex (0x...). Strings are
+// taken verbatim from the command line. Note that new string values will be
+// silently truncated to the length of the current string if the new value is
+// longer than the current string. Updating address values is currently not
+// supported. Any number of item/value pairs can be specified with a single
+// 'set' command.
+//
+// The 'setv' command is provided to set individual vector elements of
+// integral arrays.
+//
+// The 'report' command prints a report including a dump of the header and
+// section table, a listing of the types and values of all items that appear
+// in the TOC. The TOC listing includes the
+// sequence number of the entry in the TOC, the item name, the item type and
+// the item value.
+//
+// The 'attrdump' command prints a listing of the names, types and values
+// of all attribute items that appear in the TOC and their value from
+// the attribute dump file
+//
+// The 'append' command either creates or extends the section named by the
+// section argument, by appending the contents of the named file verbatim.
+// Currently the section must either be the final (highest address) section of
+// the image, or must be empty, in which case the append command creates the
+// section as the final section of the image. The 'append' command writes the
+// relocatable image address where the input file was loaded to stdout.
+//
+// The 'extract' command extracts a sections from the binary image.
+//
+// The 'delete' command deletes 0 or more sections, starting with <section0>.
+// Each section to be deleted must either be the final (highest address)
+// section of the image at the time it is deleted, or must be empty. The
+// 'delete' command writes the size of the final modified image to stdout.
+//
+// The 'dissect' command dissects the ring section named by the section argument
+// and summarizes the content of the ring section. The second argument to
+// 'dissect', i.e. [short,normal(default),long], specifies how much information
+// is included in the listing:
+// short: The bare necessities.
+// normal: Everything but a raw binary dump of the actual ring block.
+// long: Everything inclusing a raw binary dump of the actual ring block.
+// Note that iff the second argument is omitted, a 'normal' listing of the ring
+// section will occur.
+//
+// The 'disasm' command disassembles the section named by the section argument.
+//
+// The following -i<flag> are supported:
+// -ifs
+// causes the validation step to ignore image size check against the file
+// size.
+// -iv
+// causes all validation checking to be ignored. (Skips validation step.)
+
+const char* g_usage =
+ "Usage: p9_xip_tool <image> [-i<flag> ...] normalize\n"
+ " p9_xip_tool <image> [-i<flag> ...] get <item>\n"
+ " p9_xip_tool <image> [-i<flag> ...] getv <item> <index>\n"
+ " p9_xip_tool <image> [-i<flag> ...] set <item> <value> [ <item1> <value1> ... ]\n"
+ " p9_xip_tool <image> [-i<flag> ...] setv <item> <index> <value> [ <item1> <index1> <value1> ... ]\n"
+ " p9_xip_tool <image> [-i<flag> ...] report [<regex>]\n"
+ " p9_xip_tool <image> [-i<flag> ...] attrdump <attr dump file>\n"
+ " p9_xip_tool <image> [-i<flag> ...] append <section> <file>\n"
+ " p9_xip_tool <image> [-i<flag> ...] extract <section> <file>\n"
+ " p9_xip_tool <image> [-i<flag> ...] delete <section> [ <section1> ... <sectionN> ]\n"
+ " p9_xip_tool <image> [-i<flag> ...] dis <section>\n"
+ " p9_xip_tool <image> [-i<flag> ...] dissect <ring section> [short,normal(default),long]\n"
+ " p9_xip_tool <image> [-i<flag> ...] disasm <text section>\n"
+ "\n"
+ "This simple application uses the P9-XIP image APIs to normalize, search\n"
+ "update and edit P9-XIP images. This program encapsulates several commands\n"
+ "in a common command framework which requires an image to operate on, a\n"
+ "command name, and command arguments that vary by command. Commands that\n"
+ "modify the image always rewrite the image in-place in the filesystem;\n"
+ "however the original image is only modified if the command has completed\n"
+ "without error.\n"
+ "\n"
+ "The program operates on a P9-XIP format binary image, which must be\n"
+ "normalized - unless the tool is being called to normalize the image in the\n"
+ "first place using the 'normalize' command. The tool also validates the\n"
+ "image prior to operating on the image.\n"
+ "\n"
+ "The 'get' command retrieves a scalar value from the image and prints its\n"
+ "representation on stdout (followed by a newline). Scalar integer values\n"
+ "and image addresses are printed as hex numbers (0x...). Strings are printed\n"
+ "verbatim.\n"
+ "\n"
+ "The 'getv' command retrieves a vector element from the image and prints its\n"
+ "representation on stdout (followed by a newline). Integer values\n"
+ "and image addresses are printed as hex numbers (0x...). Vectors of strings\n"
+ "are not supported.\n"
+ "\n"
+ "The 'set' command allows setting integer and string values in the image.\n"
+ "New integer values can be specified in decimal or hex (0x...). Strings are\n"
+ "taken verbatim from the command line. Note that new string values will be\n"
+ "silently truncated to the length of the current string if the new value is\n"
+ "longer than the current string. Updating address values is currently not\n"
+ "supported. Any number of item/value pairs can be specified with a single\n"
+ "'set' command.\n"
+ "\n"
+ "The 'setv' command is provided to set individual vector elements of\n"
+ "integral arrays.\n"
+ "\n"
+ "The 'report' command prints a report including a dump of the header and\n"
+ "section table, a listing of the types and values of all items that appear\n"
+ "in the TOC. The TOC listing includes the\n"
+ "sequence number of the entry in the TOC, the item name, the item type and\n"
+ "the item value.\n"
+ "\n"
+ "The 'attrdump' command prints a listing of the names, types and values\n"
+ "of all attribute items that appear in the TOC and their value from \n"
+ "the attribute dump file\n"
+ "\n"
+ "The 'append' command either creates or extends the section named by the\n"
+ "section argument, by appending the contents of the named file verbatim.\n"
+ "Currently the section must either be the final (highest address) section of\n"
+ "the image, or must be empty, in which case the append command creates the\n"
+ "section as the final section of the image. The 'append' command writes the\n"
+ "relocatable image address where the input file was loaded to stdout.\n"
+ "\n"
+ "The 'extract' command extracs a sections from a binary image.\n"
+ "\n"
+ "The 'delete' command deletes 0 or more sections, starting with <section0>.\n"
+ "Each section to be deleted must either be the final (highest address)\n"
+ "section of the image at the time it is deleted, or must be empty. The\n"
+ "'delete' command writes the size of the final modified image to stdout.\n"
+ "\n"
+ "The 'dissect' command dissects the ring section named by the section argument\n"
+ "and summarizes the content of the ring section. The second argument to\n"
+ "'dissect', i.e. [short,normal(default),long], specifies how much information\n"
+ "is included in the listing:\n"
+ " short: The bare necessities.\n"
+ " normal: Everything but a raw binary dump of the actual ring block.\n"
+ " long: Everything inclusing a raw binary dump of the actual ring block.\n"
+ "Note that iff the second argument is omitted, a 'normal' listing of the ring\n"
+ "section will occur.\n"
+ "\n"
+ "The 'disasm' command disassembles the text section named by the section\n"
+ "argument.\n"
+ "\n"
+ "-i<flag>:\n"
+ "\t-ifs Causes the validation step to ignore image size check against the\n"
+ "\tfile size.\n"
+ "\t-iv Causes all validation checking to be ignored.\n"
+ ;
+
+P9_XIP_ERROR_STRINGS(g_errorStrings);
+P9_XIP_TYPE_STRINGS(g_typeStrings);
+P9_XIP_TYPE_ABBREVS(g_typeAbbrevs);
+
+P9_XIP_SECTION_NAMES_HW(g_sectionNamesHw);
+P9_XIP_SECTION_NAMES_SGPE(g_sectionNamesSgpe);
+P9_XIP_SECTION_NAMES_RESTORE(g_sectionNamesRestore);
+P9_XIP_SECTION_NAMES_CME(g_sectionNamesCme);
+P9_XIP_SECTION_NAMES_PGPE(g_sectionNamesPgpe);
+P9_XIP_SECTION_NAMES_IOPPE(g_sectionNamesIoppe);
+P9_XIP_SECTION_NAMES_FPPE(g_sectionNamesFppe);
+P9_XIP_SECTION_NAMES_SBE(g_sectionNamesSbe);
+
+// Disassembler error support.
+DIS_ERROR_STRINGS(g_errorStringsDis);
+
+#define ERRBUF_SIZE 60
+
+typedef struct
+{
+ int index;
+ int regex;
+ regex_t preg;
+} ReportControl;
+
+off_t g_imageSize;
+
+
+// Determine name of section given by its index in section table
+
+static inline const char* get_sectionName(uint64_t magic, int index)
+{
+ switch (magic)
+ {
+// case P9_XIP_MAGIC_BASE:
+// FIXME
+// break;
+// case P9_XIP_MAGIC_CENTAUR:
+// FIXME
+// break;
+ case P9_XIP_MAGIC_SEEPROM:
+ return P9_XIP_SECTION_NAME(g_sectionNamesSbe, index);
+
+ case P9_XIP_MAGIC_HW:
+ return P9_XIP_SECTION_NAME(g_sectionNamesHw, index);
+
+ case P9_XIP_MAGIC_SGPE:
+ return P9_XIP_SECTION_NAME(g_sectionNamesSgpe, index);
+
+ case P9_XIP_MAGIC_RESTORE:
+ return P9_XIP_SECTION_NAME(g_sectionNamesRestore, index);
+
+ case P9_XIP_MAGIC_CME:
+ return P9_XIP_SECTION_NAME(g_sectionNamesCme, index);
+
+ case P9_XIP_MAGIC_PGPE:
+ return P9_XIP_SECTION_NAME(g_sectionNamesPgpe, index);
+
+ case P9_XIP_MAGIC_IOPPE:
+ return P9_XIP_SECTION_NAME(g_sectionNamesIoppe, index);
+
+ case P9_XIP_MAGIC_FPPE:
+ return P9_XIP_SECTION_NAME(g_sectionNamesFppe, index);
+ }
+
+ return "";
+}
+
+// Determine index of section given by its name in section table
+
+static inline int get_sectionId(uint64_t i_magic, const char* i_section)
+{
+ int i;
+
+ for (i = 0; i < P9_XIP_SECTIONS; i++)
+ if (strcmp(i_section, get_sectionName(i_magic, i)) == 0)
+ {
+ return i;
+ }
+
+ return -1;
+}
+
+// Normalize a P9-XIP image. We normalize a copy of the image first so that
+// the original image will be available for debugging in case the
+// normalization fails, then validate and copy the normalized image back to
+// the mmap()-ed file.
+
+int
+normalize(void* io_image, const int i_argc, const char** i_argv, uint32_t i_maskIgnores)
+{
+ int rc;
+ void* copy;
+
+ do
+ {
+
+ // The 'normalize' command takes no arguments
+
+ if (i_argc != 0)
+ {
+ fprintf(stderr, g_usage);
+ exit(1);
+ }
+
+ copy = malloc(g_imageSize);
+
+ if (copy == 0)
+ {
+ perror("malloc() failed : ");
+ exit(1);
+ }
+
+ memcpy(copy, io_image, g_imageSize);
+
+ rc = p9_xip_normalize(copy);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if ( !(i_maskIgnores & P9_XIP_IGNORE_ALL) )
+ {
+ rc = p9_xip_validate2(copy, g_imageSize, i_maskIgnores);
+ }
+
+ if (rc)
+ {
+ break;
+ }
+
+ memcpy(io_image, copy, g_imageSize);
+
+ }
+ while (0);
+
+ return rc;
+}
+
+
+// Print a line of a report, listing the index, symbol, type and current
+// value.
+
+int
+tocListing(void* io_image,
+ const P9XipItem* i_item,
+ void* arg)
+{
+ int rc;
+ ReportControl* control;
+ uint64_t data;
+ char* s;
+
+ control = (ReportControl*)arg;
+
+ do
+ {
+ rc = 0;
+
+ if (control->regex)
+ {
+ if (regexec(&(control->preg), i_item->iv_id, 0, 0, 0))
+ {
+ break;
+ }
+ }
+
+ printf("0x%04x | %-42s | %s | ",
+ control->index, i_item->iv_id,
+ P9_XIP_TYPE_STRING(g_typeAbbrevs, i_item->iv_type));
+
+ switch (i_item->iv_type)
+ {
+ case P9_XIP_UINT8:
+ rc = p9_xip_get_scalar(io_image, i_item->iv_id, &data);
+
+ if (rc)
+ {
+ break;
+ }
+
+ printf("0x%02x", (uint8_t)data);
+ break;
+
+ case P9_XIP_UINT16:
+ rc = p9_xip_get_scalar(io_image, i_item->iv_id, &data);
+
+ if (rc)
+ {
+ break;
+ }
+
+ printf("0x%04x", (uint16_t)data);
+ break;
+
+ case P9_XIP_UINT32:
+ rc = p9_xip_get_scalar(io_image, i_item->iv_id, &data);
+
+ if (rc)
+ {
+ break;
+ }
+
+ printf("0x%08x", (uint32_t)data);
+ break;
+
+ case P9_XIP_UINT64:
+ rc = p9_xip_get_scalar(io_image, i_item->iv_id, &data);
+
+ if (rc)
+ {
+ break;
+ }
+
+ printf("0x%016lx", data);
+ break;
+
+ case P9_XIP_INT8:
+ rc = p9_xip_get_scalar(io_image, i_item->iv_id, &data);
+
+ if (rc)
+ {
+ break;
+ }
+
+ printf("0x%02x", (uint8_t)data);
+ break;
+
+ case P9_XIP_INT16:
+ rc = p9_xip_get_scalar(io_image, i_item->iv_id, &data);
+
+ if (rc)
+ {
+ break;
+ }
+
+ printf("0x%04x", (uint16_t)data);
+ break;
+
+ case P9_XIP_INT32:
+ rc = p9_xip_get_scalar(io_image, i_item->iv_id, &data);
+
+ if (rc)
+ {
+ break;
+ }
+
+ printf("0x%08x", (uint32_t)data);
+ break;
+
+ case P9_XIP_INT64:
+ rc = p9_xip_get_scalar(io_image, i_item->iv_id, &data);
+
+ if (rc)
+ {
+ break;
+ }
+
+ printf("0x%016lx", data);
+ break;
+
+ case P9_XIP_STRING:
+ rc = p9_xip_get_string(io_image, i_item->iv_id, &s);
+
+ if (rc)
+ {
+ break;
+ }
+
+ printf("%s", s);
+ break;
+
+ case P9_XIP_ADDRESS:
+ rc = p9_xip_get_scalar(io_image, i_item->iv_id, &data);
+
+ if (rc)
+ {
+ break;
+ }
+
+ printf("0x%04x:0x%08x",
+ (uint16_t)((data >> 32) & 0xffff),
+ (uint32_t)(data & 0xffffffff));
+ break;
+
+ default:
+ printf("unknown type\n");
+ rc = P9_XIP_BUG;
+ break;
+ }
+
+ printf("\n");
+ }
+ while (0);
+
+ control->index += 1;
+ return rc;
+}
+
+// Print a line of attribute report, listing the symbol, type and current
+// value.
+int
+attrListing(const P9XipItem* i_item)
+{
+ int rc = 0;
+ uint64_t data = 0;
+
+ if (i_item->iv_address == 0)
+ {
+ //TOC item not present in fixed section
+ return rc;
+ }
+
+ printf("%-42s | %s | ", i_item->iv_id,
+ P9_XIP_TYPE_STRING(g_typeAbbrevs, i_item->iv_type));
+
+ rc = p9_xip_get_item(i_item, &data);
+
+ if (rc)
+ {
+ return rc;
+ }
+
+ switch (i_item->iv_type)
+ {
+ case P9_XIP_UINT8:
+ printf("0x%02x", (uint8_t)data);
+ break;
+
+ case P9_XIP_UINT16:
+ printf("0x%04x", (uint16_t)data);
+ break;
+
+ case P9_XIP_UINT32:
+ printf("0x%08x", (uint32_t)data);
+ break;
+
+ case P9_XIP_UINT64:
+ printf("0x%016lx", data);
+ break;
+
+ case P9_XIP_INT8:
+ printf("0x%02x", (uint8_t)data);
+ break;
+
+ case P9_XIP_INT16:
+ printf("0x%04x", (uint16_t)data);
+ break;
+
+ case P9_XIP_INT32:
+ printf("0x%08x", (uint32_t)data);
+ break;
+
+ case P9_XIP_INT64:
+ printf("0x%016lx", data);
+ break;
+
+ case P9_XIP_STRING:
+ printf("%s", (char*)(i_item->iv_imageData));
+ break;
+
+ case P9_XIP_ADDRESS:
+ printf("0x%04x:0x%08x",
+ (uint16_t)((data >> 32) & 0xffff),
+ (uint32_t)(data & 0xffffffff));
+ break;
+
+ default:
+ printf("unknown type\n");
+ rc = P9_XIP_BUG;
+ break;
+ }
+
+ printf("\n");
+
+ return rc;
+}
+
+// Dump the image header, including the section table
+
+int
+dumpHeader(void* i_image)
+{
+ int i;
+ P9XipHeader header;
+ P9XipSection* section;
+ char magicString[9];
+
+ // Dump header information. Since the TOC may not exist we need to get
+ // the information from the header explicitly.
+
+ p9_xip_translate_header(&header, (P9XipHeader*)i_image);
+
+ memcpy(magicString, (char*)(&(((P9XipHeader*)i_image)->iv_magic)), 8);
+ magicString[8] = 0;
+
+ printf("Magic Number : 0x%016lx \"%s\"\n",
+ header.iv_magic, magicString);
+ printf("Header Version : 0x%02x\n", header.iv_headerVersion);
+ printf("Link Address : 0x%016lx\n", header.iv_linkAddress);
+ printf("L1 Loader Address : 0x%08x\n", (uint32_t)header.iv_L1LoaderAddr);
+ printf("L2 Loader Address : 0x%08x\n", (uint32_t)header.iv_L2LoaderAddr);
+ printf("Kernel Address : 0x%08x\n", (uint32_t)header.iv_kernelAddr);
+ printf("Image Size : 0x%08x (%d)\n",
+ header.iv_imageSize, header.iv_imageSize);
+ printf("Normalized : %s\n", header.iv_normalized ? "Yes" : "No");
+ printf("TOC Sorted : %s\n", header.iv_tocSorted ? "Yes" : "No");
+ printf("Build Date : %02d/%02d/%04d\n",
+ (header.iv_buildDate / 100) % 100,
+ header.iv_buildDate % 100,
+ header.iv_buildDate / 10000);
+ printf("Build Time : %02d:%02d\n",
+ header.iv_buildTime / 100,
+ header.iv_buildTime % 100);
+ printf("Build User : %s\n", header.iv_buildUser);
+ printf("Build Host : %s\n", header.iv_buildHost);
+ printf("\n");
+
+ printf("Section Table : Offset Size\n");
+ printf("\n");
+
+ for (i = 0; i < P9_XIP_SECTIONS; i++)
+ {
+ section = &(header.iv_section[i]);
+ printf("%-16s 0x%08x 0x%08x (%d)\n",
+ get_sectionName(header.iv_magic, i),
+ section->iv_offset, section->iv_size, section->iv_size);
+ }
+
+ printf("\n");
+
+ return 0;
+}
+
+
+// Print a report
+
+int
+report(void* io_image, const int i_argc, const char** i_argv)
+{
+ int rc;
+ ReportControl control;
+ char errbuf[ERRBUF_SIZE];
+
+ do
+ {
+
+ // Basic syntax check : [<regexp>]
+
+ if (i_argc > 1)
+ {
+ fprintf(stderr, g_usage);
+ exit(1);
+ }
+
+ // Compile a regular expression if supplied
+
+ if (i_argc == 1)
+ {
+ rc = regcomp(&(control.preg), i_argv[0], REG_NOSUB);
+
+ if (rc)
+ {
+ regerror(rc, &(control.preg), errbuf, ERRBUF_SIZE);
+ fprintf(stderr, "Error from regcomp() : %s\n", errbuf);
+ exit(1);
+ }
+
+ control.regex = 1;
+ }
+ else
+ {
+ control.regex = 0;
+
+ dumpHeader(io_image);
+ printf("TOC Report\n\n");
+ }
+
+ // Map the TOC with the mapReport() function
+
+ control.index = 0;
+ rc = p9_xip_map_toc(io_image, tocListing, (void*)(&control));
+
+ if (rc)
+ {
+ break;
+ }
+
+ }
+ while (0);
+
+ return rc;
+}
+
+//Print attributes from dump image
+int
+reportAttr(void* io_image, size_t i_imageSize, void* io_dump)
+{
+ int rc = 0;
+ P9XipToc* imageToc = NULL;
+ P9XipItem item = {0};
+ size_t entries = 0;
+
+ //check for seeprom image validity
+ rc = p9_xip_validate(io_image, i_imageSize);
+
+ if (rc)
+ {
+ return rc;
+ }
+
+ //get toc listing from seeprom image
+ rc = p9_xip_get_toc(io_image, &imageToc, &entries, 0, 0);
+
+ if (rc)
+ {
+ return rc;
+ }
+
+ //loop through each toc listing and print its value from pibmem dump
+ for (; entries--; imageToc++)
+ {
+ rc = p9_xip_decode_toc_dump(io_image, io_dump, imageToc, &item);
+
+ if (!rc)
+ {
+ //helper function to print the attributes
+ attrListing(&item);
+ }
+ }
+
+ return rc;
+}
+
+// Set a scalar or vector element values in the image. The 'i_setv' argument
+// indicates set/setv (0/1).
+
+int
+set(void* io_image, const int i_argc, const char** i_argv, int i_setv)
+{
+ int rc = P9_XIP_BUG, arg, base, clause_args, index_val;
+ P9XipItem item;
+ unsigned long long newValue;
+ const char* key, *index, *value;
+ char* endptr;
+
+ do
+ {
+
+ // Basic syntax check: <item> <value> [ <item1> <value1> ... ]
+ // Basic syntax check: <item> <index> <value> [ <item1> <index1> <value1> ... ]
+
+ clause_args = (i_setv ? 3 : 2);
+
+ if ((i_argc % clause_args) != 0)
+ {
+ fprintf(stderr, g_usage);
+ exit(1);
+ }
+
+ for (arg = 0; arg < i_argc; arg += clause_args)
+ {
+
+ key = i_argv[arg];
+
+ if (i_setv)
+ {
+ index = i_argv[arg + 1];
+ index_val = strtol(index, 0, 0);
+ value = i_argv[arg + 2];
+ }
+ else
+ {
+ index = "";
+ index_val = 0;
+ value = i_argv[arg + 1];
+ }
+
+ // Search for the item to see what type of data it expects, then
+ // case split on the type.
+
+ rc = p9_xip_find(io_image, key, &item);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (index_val < 0)
+ {
+ fprintf(stderr,
+ "Illegal negative vector index %s for %s\n",
+ index, key);
+ exit(1);
+ }
+ else if ((item.iv_elements != 0) &&
+ (index_val >= item.iv_elements))
+ {
+ fprintf(stderr,
+ "Index %s out-of-bounds for %s (%d elements)\n",
+ index, key, item.iv_elements);
+ exit(1);
+ }
+
+ switch (item.iv_type)
+ {
+ case P9_XIP_UINT8:
+ case P9_XIP_UINT16:
+ case P9_XIP_UINT32:
+ case P9_XIP_UINT64:
+
+ // We need to do a bit of preprocessing on the string to
+ // determine its format and set the base for strtoull(),
+ // otherwise strtoull() will be confused by leading zeros
+ // e.g. in time strings generated by `date +%H%M`, and try to
+ // process the string as octal.
+
+ if ((strlen(value) >= 2) && (value[0] == '0') &&
+ ((value[1] == 'x') || (value[1] == 'X')))
+ {
+ base = 16;
+ }
+ else
+ {
+ base = 10;
+ }
+
+ errno = 0;
+ newValue = strtoull(value, &endptr, base);
+
+ if ((errno != 0) || (endptr != (value + strlen(value))))
+ {
+ fprintf(stderr,
+ "Error parsing putative integer value : %s\n",
+ value);
+ exit(1);
+ }
+
+ switch (item.iv_type)
+ {
+
+ case P9_XIP_UINT8:
+ if ((uint8_t)newValue != newValue)
+ {
+ fprintf(stderr,
+ "Value 0x%016llx too large for 8-bit type\n",
+ newValue);
+ exit(1);
+ }
+
+ break;
+
+ case P9_XIP_UINT16:
+ if ((uint16_t)newValue != newValue)
+ {
+ fprintf(stderr,
+ "Value 0x%016llx too large for 16-bit type\n",
+ newValue);
+ exit(1);
+ }
+
+ break;
+
+ case P9_XIP_UINT32:
+ if ((uint32_t)newValue != newValue)
+ {
+ fprintf(stderr,
+ "Value 0x%016llx too large for 32-bit type\n",
+ newValue);
+ exit(1);
+ }
+
+ break;
+
+ case P9_XIP_UINT64:
+ break;
+
+ default:
+ break;
+ }
+
+ rc = p9_xip_set_element(io_image, key, index_val, newValue);
+
+ if (rc)
+ {
+ rc = P9_XIP_BUG;
+ }
+
+ break;
+
+ case P9_XIP_STRING:
+
+ if (i_setv)
+ {
+ fprintf(stderr, "Can't use 'setv' for string data %s\n",
+ key);
+ exit(1);
+ }
+
+ rc = p9_xip_set_string(io_image, key, (char*)value);
+
+ if (rc)
+ {
+ rc = P9_XIP_BUG;
+ }
+
+ break;
+
+ case P9_XIP_INT8:
+ case P9_XIP_INT16:
+ case P9_XIP_INT32:
+ case P9_XIP_INT64:
+ fprintf(stderr,
+ "Item %s has int type %s, "
+ "which is not supported for '%s'.\n",
+ i_argv[arg],
+ P9_XIP_TYPE_STRING(g_typeStrings, item.iv_type),
+ (i_setv ? "setv" : "set"));
+ exit(1);
+ break;
+
+ default:
+ fprintf(stderr,
+ "Item %s has type %s, "
+ "which is not supported for '%s'.\n",
+ i_argv[arg],
+ P9_XIP_TYPE_STRING(g_typeStrings, item.iv_type),
+ (i_setv ? "setv" : "set"));
+ exit(1);
+ break;
+ }
+
+ if (rc)
+ {
+ break;
+ }
+
+ }
+ }
+ while (0);
+
+ //if good rc, we need to msync the mmaped file to push contents to
+ //the actual file. Per man page this is required although some
+ //file systems (notably AFS) don't seem to require (GSA does)
+ if(!rc)
+ {
+ uint8_t i = 0;
+
+ do
+ {
+ rc = msync(io_image, g_imageSize , MS_SYNC);
+
+ if(rc)
+ {
+ i++;
+ fprintf(stderr,
+ "msync failed with errno %d\n", errno);
+ }
+ }
+ while(rc && i < 5);
+
+ if(rc)
+ {
+ exit(3);
+ }
+ }
+
+ return rc;
+}
+
+
+// Get a value from the image, and return on stdout. The 'i_getv' argument
+// indicates get/getv (0/1)
+
+int
+get(void* i_image, const int i_argc, const char** i_argv, int i_getv)
+{
+ int rc, nargs, index_val;
+ P9XipItem item;
+ const char* key, *index;
+ uint64_t data;
+ char* s;
+
+ do
+ {
+
+ // Basic syntax check: <item>
+ // Basic syntax check: <item> <index>
+
+ nargs = (i_getv ? 2 : 1);
+
+ if (i_argc != nargs)
+ {
+ fprintf(stderr, g_usage);
+ exit(1);
+ }
+
+ key = i_argv[0];
+
+ if (i_getv)
+ {
+ index = i_argv[1];
+ index_val = strtol(index, 0, 0);
+ }
+ else
+ {
+ index = "";
+ index_val = 0;
+ }
+
+ // Search for the item to determine its type, then case split on the
+ // type.
+
+ rc = p9_xip_find(i_image, key, &item);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (index_val < 0)
+ {
+ fprintf(stderr,
+ "Illegal negative vector index %s for %s\n",
+ index, key);
+ exit(1);
+ }
+ else if ((item.iv_elements != 0) &&
+ (index_val >= item.iv_elements))
+ {
+ fprintf(stderr, "Index %s out-of-bounds for %s (%d elements)\n",
+ index, key, item.iv_elements);
+ exit(1);
+ }
+
+ switch (item.iv_type)
+ {
+
+ case P9_XIP_UINT8:
+ case P9_XIP_UINT16:
+ case P9_XIP_UINT32:
+ case P9_XIP_UINT64:
+ rc = p9_xip_get_element(i_image, key, index_val, &data);
+
+ if (rc)
+ {
+ rc = P9_XIP_BUG;
+ break;
+ }
+
+ switch (item.iv_type)
+ {
+ case P9_XIP_UINT8:
+ printf("0x%02x\n", (uint8_t)data);
+ break;
+
+ case P9_XIP_UINT16:
+ printf("0x%04x\n", (uint16_t)data);
+ break;
+
+ case P9_XIP_UINT32:
+ printf("0x%08x\n", (uint32_t)data);
+ break;
+
+ case P9_XIP_UINT64:
+ printf("0x%016lx\n", data);
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ case P9_XIP_ADDRESS:
+ if (i_getv)
+ {
+ fprintf(stderr, "Can't use 'getv' for address data : %s\n",
+ key);
+ exit(1);
+ }
+
+ rc = p9_xip_get_scalar(i_image, key, &data);
+
+ if (rc)
+ {
+ rc = P9_XIP_BUG;
+ break;
+ }
+
+ printf("0x%012lx\n", data);
+ break;
+
+ case P9_XIP_STRING:
+ if (i_getv)
+ {
+ fprintf(stderr, "Can't use 'getv' for string data : %s\n",
+ key);
+ exit(1);
+ }
+
+ rc = p9_xip_get_string(i_image, key, &s);
+
+ if (rc)
+ {
+ rc = P9_XIP_BUG;
+ break;
+ }
+
+ printf("%s\n", s);
+ break;
+
+ default:
+ fprintf(stderr, "%s%d : Bug, unexpected type %d\n",
+ __FILE__, __LINE__, item.iv_type);
+ exit(1);
+ break;
+ }
+ }
+ while (0);
+
+ return rc;
+}
+
+
+// strtoul() with application-specific error handling
+
+unsigned long
+localStrtoul(const char* s)
+{
+ unsigned long v;
+ char* endptr;
+
+ errno = 0;
+ v = strtoul(s, &endptr, 0);
+
+ if ((errno != 0) || (endptr != (s + strlen(s))))
+ {
+ fprintf(stderr,
+ "Error parsing putative integer value : %s\n",
+ s);
+ exit(1);
+ }
+
+ return v;
+}
+
+
+// Append a file to section
+int
+append(const char* i_imageFile, const int i_imageFd, void* io_image,
+ int i_argc, const char** i_argv)
+{
+ int fileFd, newImageFd, sectionId, rc;
+ struct stat buf;
+ const char* section;
+ const char* file;
+ void* appendImage;
+ void* newImage;
+ uint32_t size, newSize, sectionOffset;
+ uint64_t homerAddress;
+ P9XipHeader header;
+
+ do
+ {
+
+ // Basic syntax check: <section> <file>
+
+ if (i_argc != 2)
+ {
+ fprintf(stderr, g_usage);
+ exit(1);
+ }
+
+ section = i_argv[0];
+ file = i_argv[1];
+
+ p9_xip_translate_header(&header, (P9XipHeader*)io_image);
+
+ // Translate the section name to a section Id
+ sectionId = get_sectionId(header.iv_magic, section);
+
+ if (sectionId < 0)
+ {
+ fprintf(stderr, "Unrecognized section name : '%s;\n", section);
+ exit(1);
+ }
+
+ // Open and mmap the file to be appended
+
+ fileFd = open(file, O_RDONLY);
+
+ if (fileFd < 0)
+ {
+ perror("open() of the file to be appended failed : ");
+ exit(1);
+ }
+
+ rc = fstat(fileFd, &buf);
+
+ if (rc)
+ {
+ perror("fstat() of the file to be appended failed : ");
+ exit(1);
+ }
+
+ appendImage = mmap(0, buf.st_size, PROT_READ, MAP_SHARED, fileFd, 0);
+
+ if (appendImage == MAP_FAILED)
+ {
+ perror("mmap() of the file to be appended failed : ");
+ exit(1);
+ }
+
+
+ // malloc() a buffer for the new image, adding space for alignment
+
+ rc = p9_xip_image_size(io_image, &size);
+
+ if (rc)
+ {
+ break;
+ }
+
+ newSize = size + buf.st_size + P9_XIP_MAX_SECTION_ALIGNMENT;
+
+ newImage = malloc(newSize);
+
+ if (newImage == 0)
+ {
+ fprintf(stderr, "Can't malloc() a buffer for the new image\n");
+ exit(1);
+ }
+
+
+ // Copy the image. At this point the original image file must be
+ // closed.
+
+ memcpy(newImage, io_image, size);
+
+ rc = close(i_imageFd);
+
+ if (rc)
+ {
+ perror("close() of the original image file failed : ");
+ exit(1);
+ }
+
+
+ // Do the append and print the image address where the data was loaded.
+ // We will not fail for unaligned addresses, as we have no knowledge
+ // of whether or why the user wants the final image address.
+
+ rc = p9_xip_append(newImage, sectionId,
+ appendImage, buf.st_size,
+ newSize, &sectionOffset);
+
+ if (rc)
+ {
+ break;
+ }
+
+ rc = p9_xip_section2image(newImage, sectionId, sectionOffset,
+ &homerAddress);
+
+ if (rc && (rc != P9_XIP_ALIGNMENT_ERROR))
+ {
+ break;
+ }
+
+ printf("0x%016lx\n", homerAddress);
+
+
+ // Now write the new image back to the filesystem
+
+ newImageFd = open(i_imageFile, O_WRONLY | O_TRUNC);
+
+ if (newImageFd < 0)
+ {
+ perror("re-open() of image file failed : ");
+ exit(1);
+ }
+
+ rc = p9_xip_image_size(newImage, &size);
+
+ if (rc)
+ {
+ break;
+ }
+
+ rc = write(newImageFd, newImage, size);
+
+ if ((rc < 0) || ((uint32_t)rc != size))
+ {
+ perror("write() of modified image failed : ");
+ exit(1);
+ }
+
+ rc = close(newImageFd);
+
+ if (rc)
+ {
+ perror("close() of modified image failed : ");
+ exit(1);
+ }
+ }
+ while (0);
+
+ return rc;
+}
+
+// Extract section from a file
+int
+extract(const char* i_imageFile, const int i_imageFd, void* io_image,
+ int i_argc, const char** i_argv)
+{
+ int fileFd, sectionId, rc;
+ void* newImage;
+ const char* section;
+ const char* file;
+ P9XipHeader header;
+ P9XipSection* xSection;
+ uint32_t size;
+ uint32_t offset;
+
+ do
+ {
+
+ if (i_argc != 2)
+ {
+ fprintf(stderr, g_usage);
+ exit(1);
+ }
+
+ section = i_argv[0];
+ file = i_argv[1];
+
+ printf("%s %s\n", section , file);
+
+ p9_xip_translate_header(&header, (P9XipHeader*)io_image);
+
+ sectionId = get_sectionId(header.iv_magic, section);
+
+ if (sectionId < 0)
+ {
+ fprintf(stderr, "Unrecognized section name : '%s;\n", section);
+ exit(1);
+ }
+
+ xSection = &(header.iv_section[sectionId]);
+
+ size = xSection->iv_size;
+ offset = xSection->iv_offset;
+
+ printf("%-16s 0x%08x 0x%08x (%d)\n",
+ section, offset, size, size);
+
+ newImage = malloc(size);
+
+ if (newImage == 0)
+ {
+ fprintf(stderr, "Can't malloc() a buffer for the new image\n");
+ exit(1);
+ }
+
+ memcpy(newImage, (void*)((uint64_t)io_image + offset), size);
+
+ fileFd = open(file, O_CREAT | O_WRONLY | O_TRUNC, 0755);
+
+ if (fileFd < 0)
+ {
+ perror("open() of the fixed section : ");
+ exit(1);
+ }
+
+ rc = write(fileFd, newImage, size);
+
+ if ((rc < 0) || ((uint32_t)rc != size))
+ {
+ perror("write() of fixed section : ");
+ exit(1);
+ }
+
+ rc = close(fileFd);
+
+ if (rc)
+ {
+ perror("close() of fixed section : ");
+ exit(1);
+ }
+
+ }
+ while (0);
+
+ return rc;
+
+}
+
+
+// Delete 0 or more sections in order.
+
+int
+deleteSection(const char* i_imageFile, const int i_imageFd, void* io_image,
+ int i_argc, const char** i_argv)
+{
+ int newImageFd, sectionId, rc, argc;
+ const char* section;
+ const char** argv;
+ void* newImage;
+ void* tempImage;
+ uint32_t size;
+ P9XipHeader header;
+
+ do
+ {
+
+ // malloc() a buffer for the new image
+
+ rc = p9_xip_image_size(io_image, &size);
+
+ if (rc)
+ {
+ break;
+ }
+
+ newImage = malloc(size);
+
+ if (newImage == 0)
+ {
+ fprintf(stderr, "Can't malloc() a buffer for the new image\n");
+ exit(1);
+ }
+
+
+ // Copy the image. At this point the original image file must be
+ // closed.
+
+ memcpy(newImage, io_image, size);
+
+ rc = close(i_imageFd);
+
+ if (rc)
+ {
+ perror("close() of the original image file failed : ");
+ exit(1);
+ }
+
+ // Create a temporary place holder for image
+
+ tempImage = malloc(size);
+
+ if (tempImage == 0)
+ {
+ fprintf(stderr, "Can't malloc() a buffer for the temporary image\n");
+ exit(1);
+ }
+
+
+ p9_xip_translate_header(&header, (P9XipHeader*)io_image);
+
+ // Delete the sections in argument order
+
+ for (argc = i_argc, argv = i_argv; argc != 0; argc--, argv++)
+ {
+
+ // Translate the section name to a section Id
+
+ section = *argv;
+
+ sectionId = get_sectionId(header.iv_magic, section);
+
+ if (sectionId < 0)
+ {
+ fprintf(stderr, "Unrecognized section name : '%s;\n", section);
+ exit(1);
+ }
+
+ // Delete the section
+
+ rc = p9_xip_delete_section(newImage, tempImage, size, sectionId);
+
+ if (rc)
+ {
+ break;
+ }
+ }
+
+ if (rc)
+ {
+ break;
+ }
+
+ // Print the final size of the new image
+
+ rc = p9_xip_image_size(newImage, &size);
+
+ if (rc)
+ {
+ break;
+ }
+
+ printf("%u\n", size);
+
+ // Now write the new image back to the filesystem
+
+ newImageFd = open(i_imageFile, O_WRONLY | O_TRUNC);
+
+ if (newImageFd < 0)
+ {
+ perror("re-open() of image file failed : ");
+ exit(1);
+ }
+
+ rc = write(newImageFd, newImage, size);
+
+ if ((rc < 0) || ((uint32_t)rc != size))
+ {
+ perror("write() of modified image failed : ");
+ exit(1);
+ }
+
+ rc = close(newImageFd);
+
+ if (rc)
+ {
+ perror("close() of modified image failed : ");
+ exit(1);
+ }
+ }
+ while (0);
+
+ return rc;
+}
+
+
+// 'TEST' is an undocumented command provided to test the APIs. It searches
+// and modifies a copy of the image but puts the image back together as it
+// was, then verifies that the the original image and the copy are identical.
+
+#define BOMB_IF(test) \
+ if (test) { \
+ fprintf(stderr, "%s:%d : Error in TEST\n", \
+ __FILE__, __LINE__); \
+ exit(1); \
+ }
+
+#define BOMB_IF_RC \
+ if (rc) { \
+ fprintf(stderr, "%s:%d : Error in TEST, rc = %s\n", \
+ __FILE__, __LINE__, \
+ P9_XIP_ERROR_STRING(g_errorStrings, rc)); \
+ exit(1); \
+ }
+
+
+int
+TEST(void* io_image, const int i_argc, const char** i_argv)
+{
+ int rc;
+ uint64_t linkAddress, entryPoint, data, data1, magicKey, L1_LoaderAddr[2];
+ char* key, *revision, *revdup, *longString, *shortString;
+ void* originalImage;
+ uint32_t imageSize;
+ P9XipItem item;
+ P9XipHeader header;
+ P9XipSection section;
+ //ProcSbeFixed* fixed;
+ uint32_t tocSize;
+
+ do
+ {
+ rc = p9_xip_image_size(io_image, &imageSize);
+ BOMB_IF_RC;
+ originalImage = malloc(imageSize);
+ BOMB_IF(originalImage == 0);
+ memcpy(originalImage, io_image, imageSize);
+
+ rc = p9_xip_get_scalar(io_image, "toc_sorted", &data);
+ BOMB_IF_RC;
+ BOMB_IF(data != 1);
+
+ rc = p9_xip_get_scalar(io_image, "image_size", &data);
+ BOMB_IF_RC;
+ BOMB_IF(data != (uint64_t)g_imageSize);
+
+ rc = p9_xip_get_scalar(io_image, "magic", &magicKey);
+ BOMB_IF_RC;
+
+ switch (magicKey)
+ {
+ case P9_XIP_MAGIC_BASE:
+ key = (char*)"proc_p9_fabricinit_revision";
+ rc = p9_xip_get_string(io_image, key, &revision);
+ BOMB_IF_RC;
+ BOMB_IF(strncmp(revision, "1.", 2) != 0);
+ break;
+
+ case P9_XIP_MAGIC_SEEPROM:
+ key = (char*)"";
+ // Can't do this test here as the TOC has been stripped
+ break;
+
+ case P9_XIP_MAGIC_CENTAUR:
+ key = (char*)"cen_p9_initf_revision";
+ rc = p9_xip_get_string(io_image, key, &revision);
+ BOMB_IF_RC;
+ BOMB_IF(strncmp(revision, "1.", 2) != 0);
+ break;
+
+ default:
+ BOMB_IF(1);
+ break;
+ }
+
+ rc = p9_xip_get_scalar(io_image, "link_address", &linkAddress);
+ BOMB_IF_RC;
+
+ if (magicKey != P9_XIP_MAGIC_SEEPROM)
+ {
+ rc = p9_xip_get_scalar(io_image, "entry_point", &entryPoint);
+ BOMB_IF_RC;
+ }
+
+ rc = p9_xip_get_scalar(io_image, "L1_LoaderAddr", &data);
+ BOMB_IF_RC;
+ BOMB_IF((magicKey != P9_XIP_MAGIC_SEEPROM) && (entryPoint != (linkAddress + data)));
+
+ rc =
+ p9_xip_set_scalar(io_image, "toc_sorted", 0) ||
+ p9_xip_set_scalar(io_image, "image_size", 0);
+ BOMB_IF_RC;
+
+ data = 0;
+ data += (rc = p9_xip_get_scalar(io_image, "toc_sorted", &data), data);
+ BOMB_IF_RC;
+ data += (rc = p9_xip_get_scalar(io_image, "image_size", &data), data);
+ BOMB_IF_RC;
+ BOMB_IF(data != 0);
+
+ // Write back keys found during read check.
+
+ rc =
+ p9_xip_set_scalar(io_image, "toc_sorted", 1) ||
+ p9_xip_set_scalar(io_image, "image_size", g_imageSize);
+ BOMB_IF_RC;
+
+ // We'll rewrite the revision keyword with a long string and a short
+ // string, and verify that rewriting is being done correctly. In the
+ // end we copy the original revision string back in, which is safe
+ // because the memory allocation for strings does not change when they
+ // are modified.
+
+ revdup = strdup(revision);
+ longString = (char*)"A very long string";
+ shortString = (char*)"?";
+
+ if (magicKey != P9_XIP_MAGIC_SEEPROM)
+ {
+ rc =
+ p9_xip_set_string(io_image, key, longString) ||
+ p9_xip_get_string(io_image, key, &revision);
+ BOMB_IF_RC;
+ BOMB_IF((strlen(revision) != strlen(revdup)) ||
+ (strncmp(revision, longString, strlen(revdup)) != 0));
+
+ rc =
+ p9_xip_set_string(io_image, key, shortString) ||
+ p9_xip_get_string(io_image, key, &revision);
+ BOMB_IF_RC;
+ BOMB_IF(strcmp(revision, shortString) != 0);
+
+ memcpy(revision, revdup, strlen(revdup) + 1);
+ }
+
+ // Use p9_xip_[read,write]_uint64 to modify the image and restore it
+ // to its original form.
+
+ rc = p9_xip_find(io_image, "L1_LoaderAddr", &item);
+ BOMB_IF_RC;
+ rc = p9_xip_get_scalar(io_image, "L1_LoaderAddr", &(L1_LoaderAddr[0]));
+ BOMB_IF_RC;
+
+ rc = p9_xip_read_uint64(io_image, item.iv_address, &(L1_LoaderAddr[1]));
+ BOMB_IF_RC;
+ BOMB_IF(L1_LoaderAddr[0] != L1_LoaderAddr[1]);
+
+ rc = p9_xip_write_uint64(io_image, item.iv_address,
+ 0xdeadbeefdeadc0deull);
+ BOMB_IF_RC;
+ rc = p9_xip_read_uint64(io_image, item.iv_address, &(L1_LoaderAddr[1]));
+ BOMB_IF_RC;
+ BOMB_IF(L1_LoaderAddr[1] != 0xdeadbeefdeadc0deull);
+
+ rc = p9_xip_write_uint64(io_image, item.iv_address, L1_LoaderAddr[0]);
+ BOMB_IF_RC;
+
+ // Try p9_xip_get_section against the translated header
+
+ p9_xip_translate_header(&header, (P9XipHeader*)io_image);
+ rc = p9_xip_get_section(io_image, P9_XIP_SECTION_TOC, &section);
+ BOMB_IF_RC;
+ BOMB_IF((section.iv_size !=
+ header.iv_section[P9_XIP_SECTION_TOC].iv_size));
+
+
+ // Make sure the .fixed section access compiles and seems to
+ // work. Modify an entry via the .fixed and verify it with normal TOC
+ // access.
+
+ if (magicKey == P9_XIP_MAGIC_SEEPROM)
+ {
+
+ BOMB_IF(0 != 0);
+
+ exit(1);
+
+ rc = p9_xip_get_scalar(io_image, "proc_p9_ex_dpll_initf_control",
+ &data);
+ BOMB_IF_RC;
+ //fixed =
+ //(ProcSbeFixed*)((unsigned long)io_image + P9_XIP_FIXED_OFFSET);
+ //fixed->proc_p9_ex_dpll_initf_control = 0xdeadbeefdeadc0deull;
+ rc = p9_xip_get_scalar(io_image, "proc_p9_ex_dpll_initf_control",
+ &data1);
+ BOMB_IF_RC;
+#ifdef _BIG_ENDIAN
+ BOMB_IF(data1 != 0xdeadbeefdeadc0deull);
+#else
+ BOMB_IF(data1 != 0xdec0addeefbeaddeull);
+#endif
+ rc = p9_xip_set_scalar(io_image, "proc_p9_ex_dpll_initf_control",
+ data);
+ BOMB_IF_RC;
+ }
+
+ // Temporarily "delete" the .toc section and try to get/set via the
+ // mini-TOC for .fixed, and make sure that we can't get things that
+ // are not in the mini-toc.
+
+ tocSize =
+ ((P9XipHeader*)io_image)->iv_section[P9_XIP_SECTION_TOC].iv_size;
+
+ ((P9XipHeader*)io_image)->iv_section[P9_XIP_SECTION_TOC].iv_size =
+ 0;
+
+ rc = p9_xip_get_scalar(io_image, "proc_p9_ex_dpll_initf_control",
+ &data);
+ rc = p9_xip_set_scalar(io_image, "proc_p9_ex_dpll_initf_control",
+ 0xdeadbeef);
+ rc = p9_xip_get_scalar(io_image, "proc_p9_ex_dpll_initf_control",
+ &data1);
+ BOMB_IF(data1 != 0xdeadbeef);
+ rc = p9_xip_set_scalar(io_image, "proc_p9_ex_dpll_initf_control",
+ data);
+ BOMB_IF_RC;
+
+ BOMB_IF(p9_xip_find(io_image, "proc_p9_ex_dpll_initf", 0) !=
+ P9_XIP_ITEM_NOT_FOUND);
+
+ ((P9XipHeader*)io_image)->iv_section[P9_XIP_SECTION_TOC].iv_size =
+ tocSize;
+
+ if (magicKey != P9_XIP_MAGIC_SEEPROM)
+ {
+ BOMB_IF(p9_xip_find(io_image, "proc_p9_ex_dpll_initf", 0) != 0);
+ }
+
+
+#ifdef DEBUG_P9_XIP_IMAGE
+ printf("\nYou will see an expected warning below "
+ "about P9_XIP_WOULD_OVERFLOW\n"
+ "It means the TEST is working (not failing)\n\n");
+#endif
+
+ // Finally compare against the original
+
+ BOMB_IF(memcmp(io_image, originalImage, imageSize));
+
+ }
+ while (0);
+
+ return rc;
+}
+
+
+
+#ifdef XIP_TOOL_ENABLE_DISSECT
+
+// This should be improved, though. Not really our responsibility defining this.
+#define CHIPLET_ID_MAX (uint8_t)0x37
+
+/// Function: dissectRingSectionTor()
+///
+/// Brief: Dissects and summarizes content of a ring section.
+///
+/// \param[in] i_ringSection A pointer to a TOR compliant ring section.
+///
+/// \param[in] i_imageMagicNo The image's MAGIC number.
+///
+/// \param[in] i_listingModeId The listing mode: {short, normal(default), long}.
+///
+/// Assumptions:
+///
+int dissectRingSectionTor( void* i_ringSection,
+ uint64_t i_imageMagicNo,
+ uint8_t i_listingModeId )
+{
+ int rc = 0;
+ uint32_t i;
+ char* disList = NULL;
+ uint32_t sizeDisLine = 0, sizeList = 0, sizeListMax = 0, sizeListIncr;
+ char lineDis[LINE_SIZE_MAX];
+ uint32_t numDdLevels;
+ uint8_t iDdLevel, ddLevel;
+ uint8_t ppeType;
+ uint8_t ringId;
+ RingType_t ringType;
+ uint8_t ringVariant;
+ uint8_t instanceId;
+ void* ringBlockPtr;
+ uint32_t ringBlockSize;
+ char ringName[32];
+ void* hostRs4Container;
+ uint32_t compressedBits = 0, ringLength = 0;
+ double compressionPct = 0;
+ uint32_t ringSeqNo = 0; // Ring sequence number
+
+ //
+ // Allocate buffer to hold dissected ring info. (Start out with min 10kB buffer size.)
+ //
+ sizeListIncr = 10 * LINE_SIZE_MAX;
+ sizeListMax = sizeListIncr;
+ disList = (char*)malloc(sizeListMax);
+
+ if (disList == NULL)
+ {
+ fprintf( stderr, "ERROR : malloc() failed.\n");
+ fprintf( stderr, "\tMore info: %s\n", DIS_ERROR_STRING(g_errorStringsDis, DIS_MEMORY_ERROR));
+ return P9_XIP_DISASSEMBLER_ERROR;
+ }
+
+ *disList = '\0'; // Make sure the buffer is NULL terminated (though probably not needed.)
+ sizeList = 0;
+
+ sizeDisLine = snprintf( lineDis, LINE_SIZE_MAX,
+ "-----------------------------\n"
+ "* Ring summary *\n");
+
+ disList = strcat(disList, lineDis);
+ sizeList = sizeList + sizeDisLine;
+
+ //
+ // Allocate large buffer to hold max length ring block.
+ //
+ ringBlockSize = RING_BUF_SIZE_MAX;
+ ringBlockPtr = malloc(ringBlockSize);
+
+ //
+ // Get number of DD levels from TOR structure in ring section
+ //
+ if (i_imageMagicNo == P9_XIP_MAGIC_HW)
+ {
+ numDdLevels = htobe32( ( (TorNumDdLevels_t*)i_ringSection )->TorNumDdLevels );
+ fprintf( stdout, "numDdLevels (=%d) read from top of ring section.\n", numDdLevels);
+ }
+ else
+ {
+ numDdLevels = 1;
+ ddLevel = 0xff; // This means it's unknown.
+ fprintf( stdout, "Image contains only one DD level set of rings.\n");
+ }
+
+ //----------------
+ // DD level loop.
+ for (iDdLevel = 0; iDdLevel < numDdLevels; iDdLevel++)
+ {
+
+ if (i_imageMagicNo == P9_XIP_MAGIC_HW)
+ {
+ ddLevel = ( ( htobe32( ( ( (TorDdLevelBlock_t*)((uintptr_t)i_ringSection + sizeof(TorNumDdLevels_t)) ) +
+ iDdLevel )->TorDdLevelAndOffset ) & 0xff000000 ) >> 24 );
+ }
+
+ //----------------
+ // PPE type loop.
+ // - SBE, CME, SGPE
+ for (ppeType = 0; ppeType < NUM_PPE_TYPES; ppeType++)
+ {
+
+ //--------------------
+ // Ring variant loop.
+ // - Base, cache, risk, override, overlay
+ for (ringVariant = 0; ringVariant < NUM_RING_VARIANTS; ringVariant++)
+ {
+
+ //----------------------
+ // Unique ring ID loop.
+ for (ringId = 0; ringId < NUM_RING_IDS; ringId++)
+ {
+
+ ringType = (RingType_t)(-1);
+
+ //---------------------------
+ // Chiplet instance ID loop.
+ // - Only loop once if ringId is a common ring.
+ for (instanceId = 0; instanceId <= CHIPLET_ID_MAX && ringType != COMMON; instanceId++)
+ {
+
+ fprintf( stdout, "Processing: "
+ "DD=0x%02x "
+ "PPE=%s "
+ "Variant=%s "
+ "RingID=%d "
+ "InstanceID=0x%02x\n",
+ ddLevel, ppeTypeName[ppeType], ringVariantName[ringVariant], ringId, instanceId);
+
+ ringBlockSize = RING_BUF_SIZE_MAX;
+ rc = tor_access_ring( i_ringSection,
+ i_imageMagicNo,
+ (RingID)ringId,
+ ddLevel,
+ (PpeType_t)ppeType,
+ ringType, // IO parm
+ (RingVariant_t)ringVariant,
+ instanceId, // IO parm
+ GET_SINGLE_RING,
+ &ringBlockPtr, // IO parm
+ ringBlockSize, // IO parm
+ ringName,
+ 0 );
+
+ // Gather ring details and print it.
+ //
+ if (rc == IMGBUILD_TGR_RING_FOUND)
+ {
+
+ // Check ring block size.
+ if ( htobe32(((RingLayout_t*)ringBlockPtr)->sizeOfThis) != ringBlockSize )
+ {
+ fprintf(stderr, "tor_access_ring() was successful and found a ring but "
+ "sizeOfThis(=0x%08x) != ringBlockSize(=0x%08x) is a bug.\n",
+ htobe32(((RingLayout_t*)ringBlockPtr)->sizeOfThis), ringBlockSize);
+ exit(1);
+ }
+
+ ringSeqNo++;
+
+ // Summarize a few key characteristics of the ring block if "short".
+ if (i_listingModeId == LMID_SHORT)
+ {
+ sizeDisLine = snprintf( lineDis, LINE_SIZE_MAX,
+ "-----------------------------\n"
+ "%i.\n"
+ "ddLevel = 0x%02x\n"
+ "ppeType = %s\n"
+ "ringName = %s\n"
+ "ringVariant = %s\n"
+ "instanceId = 0x%02x\n",
+ ringSeqNo, ddLevel, ppeTypeName[ppeType], ringName,
+ ringVariantName[ringVariant], instanceId );
+
+ if (sizeDisLine >= LINE_SIZE_MAX)
+ {
+ fprintf(stderr, "The max print line size, LINE_SIZE_MAX=%d, has been reached.(1)",
+ LINE_SIZE_MAX);
+ fprintf(stderr, "You should investigate why this happened before increasing "
+ "the value of LINE_SIZE_MAX since something might be wrong "
+ "with the RS4 ring content.");
+ exit(1);
+ }
+
+ // Update list buffer and readjust list buffer size, if needed.
+ disList = strcat(disList, lineDis);
+ sizeList = sizeList + sizeDisLine;
+
+ }
+
+ // Summarize all characteristics of the ring block if "normal" or "long" (default).
+ if ( i_listingModeId == LMID_NORMAL || i_listingModeId == LMID_LONG )
+ {
+ // Calculate RS4 compression efficiency.
+ hostRs4Container = (void*)( (uintptr_t)ringBlockPtr + sizeof(RingLayout_t) );
+ compressedBits = htobe32(((CompressedScanData*)hostRs4Container)->iv_algorithmReserved) * 4;
+ ringLength = htobe32(((CompressedScanData*)hostRs4Container)->iv_length);
+ compressionPct = (double)compressedBits / (double)ringLength * 100.0;
+
+ sizeDisLine = snprintf( lineDis, LINE_SIZE_MAX,
+ "-----------------------------\n"
+ "%i.\n"
+ "ddLevel = 0x%02x\n"
+ "ppeType = %s\n"
+ "ringId = %u\n"
+ "ringName = %s\n"
+ "ringVariant = %s\n"
+ "instanceId = 0x%02x\n"
+ "ringBlockSize = 0x%08x\n"
+ "RS4 ring size [bits] = %u\n"
+ "Raw ring size [bits] = %u\n"
+ "Compression [%%] = %0.2f\n",
+ ringSeqNo, ddLevel, ppeTypeName[ppeType], ringId, ringName,
+ ringVariantName[ringVariant], instanceId,
+ ringBlockSize, compressedBits, ringLength, compressionPct );
+
+ if (sizeDisLine >= LINE_SIZE_MAX)
+ {
+ fprintf(stderr, "The max print line size, LINE_SIZE_MAX=%d, has been reached.(2)",
+ LINE_SIZE_MAX);
+ fprintf(stderr, "You should investigate why this happened before increasing "
+ "the value of LINE_SIZE_MAX since something might be wrong "
+ "with the RS4 ring content.");
+ exit(1);
+ }
+
+ // Update list buffer and readjust list buffer size, if needed.
+ disList = strcat(disList, lineDis);
+ sizeList = sizeList + sizeDisLine;
+
+ }
+
+ // Dump ring block if "long".
+ if (i_listingModeId == LMID_LONG)
+ {
+ sizeDisLine = snprintf( lineDis, LINE_SIZE_MAX,
+ "Binary ring block dump (LE format):\n");
+ disList = strcat(disList, lineDis);
+ sizeList = sizeList + sizeDisLine;
+
+ if (sizeDisLine >= LINE_SIZE_MAX)
+ {
+ fprintf(stderr, "The max print line size, LINE_SIZE_MAX=%d, has been reached.(3)",
+ LINE_SIZE_MAX);
+ fprintf(stderr, "You should investigate why this happened before increasing "
+ "the value of LINE_SIZE_MAX since something might be wrong "
+ "with the RS4 ring content.");
+ exit(1);
+ }
+
+ for (i = 0; i < ringBlockSize / 8; i++)
+ {
+ sizeDisLine = snprintf( lineDis, LINE_SIZE_MAX,
+ "%04x: %04x %04x %04x %04x\n",
+ i * 8,
+ (uint16_t)( htobe64(*((uint64_t*)ringBlockPtr + i)) >> 48),
+ (uint16_t)( htobe64(*((uint64_t*)ringBlockPtr + i)) >> 32),
+ (uint16_t)( htobe64(*((uint64_t*)ringBlockPtr + i)) >> 16),
+ (uint16_t)( htobe64(*((uint64_t*)ringBlockPtr + i))) );
+
+ disList = strcat(disList, lineDis);
+ sizeList = sizeList + sizeDisLine;
+
+ }
+ }
+
+ if (sizeList > (sizeListMax - LINE_SIZE_MAX))
+ {
+ sizeListMax = sizeListMax + sizeListIncr;
+ disList = (char*)realloc( (void*)(disList), sizeListMax);
+ }
+
+ fprintf(stdout, "%s\n", disList);
+
+ }
+ else if (rc == IMGBUILD_TGR_RING_NOT_FOUND)
+ {
+ fprintf(stdout, "tor_access_ring() returned rc=%d=IMGBUILD_TGR_RING_NOT_FOUND\n", rc);
+ }
+ else if (rc == IMGBUILD_INVALID_INSTANCEID)
+ {
+ fprintf(stdout, "tor_access_ring() returned rc=%d=IMGBUILD_INVALID_INSTANCEID\n", rc);
+ }
+ else if (rc == IMGBUILD_TGR_AMBIGUOUS_API_PARMS)
+ {
+ fprintf(stdout, "tor_access_ring() returned rc=%d=IMGBUILD_TGR_AMBIGUOUS_API_PARMS\n", rc);
+ }
+ else
+ {
+ fprintf(stderr, "tor_access_ring() returned error code rc=%d\n", rc);
+ exit(1);
+ }
+
+ } // End of for(instanceId)
+
+ } // End of for(ringVariant)
+
+ } // End of for(iRingId)
+
+ } // End of for(ppeType)
+
+ } // End of for(iDdLevel)
+
+
+ sizeDisLine = snprintf( lineDis, LINE_SIZE_MAX,
+ "-----------------------------\n");
+
+ disList = strcat(disList, lineDis);
+ sizeList = sizeList + sizeDisLine;
+
+ // Adjust final buffer size, add 1 for NULL char and print it.
+ if (disList)
+ {
+ disList = (char*)realloc( (void*)(disList), sizeList + 1);
+ fprintf(stdout, "%s\n", disList);
+ free(disList);
+ }
+
+ return 0;
+
+}
+
+
+
+/// Function: dissectRingSection()
+///
+/// Brief: Processes XIP tool input parms and prepares parameters to be passed
+/// to dissectRingSectionTor which does the actual dissection and
+/// summarizing of the ring section.
+///
+/// \param[in] i_image A pointer to a P9-XIP image in host memory.
+///
+/// \param[in] i_argc Additional number of arguments beyond "dissect" keyword.
+///
+/// \param[in] i_argv Additional arguments beyond "dissect" keyword.
+///
+/// Assumptions:
+///
+int dissectRingSection(void* i_image,
+ int i_argc,
+ const char** i_argv)
+{
+ int rc = 0;
+ const char* sectionName;
+ const char* listingModeName = NULL;
+ uint8_t sectionId, listingModeId;
+ P9XipHeader hostHeader;
+ P9XipSection hostSection;
+ void* ringSectionPtr;
+
+
+ if (i_argc != 1 && i_argc != 2)
+ {
+ fprintf(stderr, g_usage);
+ exit(1);
+ }
+
+ if (i_argc == 1)
+ {
+ sectionName = i_argv[0];
+ }
+ else
+ {
+ sectionName = i_argv[0];
+ listingModeName = i_argv[1];
+ }
+
+ p9_xip_translate_header(&hostHeader, (P9XipHeader*)i_image);
+
+ // Determine P9-XIP ring section ID from the section name, e.g.
+ // .rings => P9_XIP_SECTION_HW_RINGS
+ if (strcmp(sectionName, ".rings") == 0)
+ {
+ if (hostHeader.iv_magic == P9_XIP_MAGIC_SEEPROM)
+ {
+ sectionId = P9_XIP_SECTION_SBE_RINGS;
+ }
+ else if (hostHeader.iv_magic == P9_XIP_MAGIC_HW)
+ {
+ sectionId = P9_XIP_SECTION_HW_RINGS;
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: .rings is not a valid section for image w/magic=0x%016lx\n",
+ hostHeader.iv_magic);
+ exit(1);
+ }
+ }
+ else if (strcmp(sectionName, ".overrides") == 0)
+ {
+ if (hostHeader.iv_magic == P9_XIP_MAGIC_SEEPROM)
+ {
+ sectionId = P9_XIP_SECTION_SBE_OVERRIDES;
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: .overrides is not a valid section for image w/magic=0x%016lx\n",
+ hostHeader.iv_magic);
+ exit(1);
+ }
+ }
+ else if (strcmp(sectionName, ".overlays") == 0)
+ {
+ if (hostHeader.iv_magic == P9_XIP_MAGIC_SEEPROM)
+ {
+ sectionId = P9_XIP_SECTION_SBE_OVERLAYS;
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: .overlays is not a valid section for image w/magic=0x%016lx\n",
+ hostHeader.iv_magic);
+ exit(1);
+ }
+ }
+ else
+ {
+ fprintf(stderr, "ERROR : %s is an invalid ring section name.\n", sectionName);
+ fprintf(stderr, "Valid ring <section> names for the 'dissect' function are:\n");
+ fprintf(stderr, "\t.rings\n");
+ fprintf(stderr, "\t.overrides\n");
+ fprintf(stderr, "\t.overlays\n");
+ exit(1);
+ }
+
+ // Determine mode of listing.
+ //
+ if ( listingModeName == NULL )
+ {
+ listingModeId = LMID_NORMAL;
+ }
+ else if (strcmp(listingModeName, "short") == 0)
+ {
+ listingModeId = LMID_SHORT;
+ }
+ else if (strcmp(listingModeName, "normal") == 0)
+ {
+ listingModeId = LMID_NORMAL;
+ }
+ else if (strcmp(listingModeName, "long") == 0)
+ {
+ listingModeId = LMID_LONG;
+ }
+ else
+ {
+ fprintf(stderr, "ERROR : %s is an invalid listing mode name.\n", listingModeName);
+ fprintf(stderr, "Valid listing mode names the 'dissect' function are:\n");
+ fprintf(stderr, "\tshort\n");
+ fprintf(stderr, "\tnormal (default if omitted)\n");
+ fprintf(stderr, "\tlong\n");
+ exit(1);
+ }
+
+ // Get ring section.
+ //
+ rc = p9_xip_get_section( i_image, sectionId, &hostSection);
+
+ if (rc)
+ {
+ fprintf( stderr, "p9_xip_get_section() failed : %s\n", P9_XIP_ERROR_STRING(g_errorStrings, rc));
+ return P9_XIP_DISASSEMBLER_ERROR;
+ }
+
+ if (hostSection.iv_offset == 0)
+ {
+ fprintf( stdout, "Ring section (w/ID=%d) is empty. Nothing to do. Quitting.\n", sectionId);
+ exit(1);
+ }
+
+ ringSectionPtr = (void*)(hostSection.iv_offset + (uintptr_t)i_image);
+
+ rc = dissectRingSectionTor(ringSectionPtr, hostHeader.iv_magic, listingModeId);
+
+ return rc;
+
+}
+
+#endif
+
+
+
+/// Function: openAndMap()
+///
+/// Brief: Opens and mmaps the file.
+///
+void
+openAndMap(const char* i_fileName, int i_writable, int* o_fd, void** o_image, const uint32_t i_maskIgnores)
+{
+ int rc, openMode, mmapProt, mmapShared;
+ struct stat buf;
+
+ if (i_writable)
+ {
+ openMode = O_RDWR;
+ mmapProt = PROT_READ | PROT_WRITE;
+ mmapShared = MAP_SHARED;
+ }
+ else
+ {
+ openMode = O_RDONLY;
+ mmapProt = PROT_READ;
+ mmapShared = MAP_PRIVATE;
+ }
+
+ *o_fd = open(i_fileName, openMode);
+
+ if (*o_fd < 0)
+ {
+ perror("open() of the image failed : ");
+ exit(1);
+ }
+
+ rc = fstat(*o_fd, &buf);
+
+ if (rc)
+ {
+ perror("fstat() of the image failed : ");
+ exit(1);
+ }
+
+ g_imageSize = buf.st_size;
+
+ *o_image = mmap(0, g_imageSize, mmapProt, mmapShared, *o_fd, 0);
+
+ if (*o_image == MAP_FAILED)
+ {
+ perror("mmap() of the image failed : ");
+ exit(1);
+ }
+
+ if ( !(i_maskIgnores & P9_XIP_IGNORE_ALL) )
+ {
+ rc = p9_xip_validate2(*o_image, g_imageSize, i_maskIgnores);
+
+ if (rc)
+ {
+ fprintf(stderr, "p9_xip_validate2() failed : %s\n",
+ P9_XIP_ERROR_STRING(g_errorStrings, rc));
+ exit(1);
+ }
+ }
+
+}
+
+
+static inline void
+openAndMapWritable(const char* i_imageFile, int* o_fd, void** o_image, const uint32_t i_maskIgnores)
+{
+ openAndMap(i_imageFile, 1, o_fd, o_image, i_maskIgnores);
+}
+
+
+static inline void
+openAndMapReadOnly(const char* i_imageFile, int* o_fd, void** o_image, const uint32_t i_maskIgnores)
+{
+ openAndMap(i_imageFile, 0, o_fd, o_image, i_maskIgnores);
+}
+
+
+// Parse and execute a pre-tokenized command
+
+void
+command(const char* i_imageFile, const int i_argc, const char** i_argv, const uint32_t i_maskIgnores)
+{
+ void* image;
+ void* attrDump;
+ int fd, rc = 0;
+
+ if (strcmp(i_argv[0], "normalize") == 0)
+ {
+
+ openAndMapWritable(i_imageFile, &fd, &image, i_maskIgnores);
+ rc = normalize(image, i_argc - 1, &(i_argv[1]), i_maskIgnores);
+
+ }
+ else if (strcmp(i_argv[0], "set") == 0)
+ {
+
+ openAndMapWritable(i_imageFile, &fd, &image, i_maskIgnores);
+ rc = set(image, i_argc - 1, &(i_argv[1]), 0);
+
+ }
+ else if (strcmp(i_argv[0], "setv") == 0)
+ {
+
+ openAndMapWritable(i_imageFile, &fd, &image, i_maskIgnores);
+ rc = set(image, i_argc - 1, &(i_argv[1]), 1);
+
+ }
+ else if (strcmp(i_argv[0], "get") == 0)
+ {
+
+ openAndMapReadOnly(i_imageFile, &fd, &image, i_maskIgnores);
+ rc = get(image, i_argc - 1, &(i_argv[1]), 0);
+
+ }
+ else if (strcmp(i_argv[0], "getv") == 0)
+ {
+
+ openAndMapReadOnly(i_imageFile, &fd, &image, i_maskIgnores);
+ rc = get(image, i_argc - 1, &(i_argv[1]), 1);
+
+ }
+ else if (strcmp(i_argv[0], "report") == 0)
+ {
+
+ openAndMapReadOnly(i_imageFile, &fd, &image, i_maskIgnores);
+ rc = report(image, i_argc - 1, &(i_argv[1]));
+
+ }
+ else if (strcmp(i_argv[0], "attrdump") == 0)
+ {
+
+ openAndMapReadOnly(i_imageFile, &fd, &image, i_maskIgnores);
+ //capture the g_imageSize size for validation, since the next
+ //openAndMapReadOnly will overwrite it
+ size_t imageSize = g_imageSize;
+ //first argument after command is dump file
+ openAndMapReadOnly(i_argv[1], &fd, &attrDump, P9_XIP_IGNORE_ALL);
+ rc = reportAttr(image, imageSize, attrDump);
+
+ }
+ else if (strcmp(i_argv[0], "append") == 0)
+ {
+
+ openAndMapWritable(i_imageFile, &fd, &image, i_maskIgnores);
+ rc = append(i_imageFile, fd, image, i_argc - 1, &(i_argv[1]));
+
+ }
+ else if (strcmp(i_argv[0], "extract") == 0)
+ {
+
+ openAndMapWritable(i_imageFile, &fd, &image, i_maskIgnores);
+ rc = extract(i_imageFile, fd, image, i_argc - 1, &(i_argv[1]));
+
+ }
+ else if (strcmp(i_argv[0], "delete") == 0)
+ {
+
+ openAndMapWritable(i_imageFile, &fd, &image, i_maskIgnores);
+ rc = deleteSection(i_imageFile, fd, image, i_argc - 1,
+ &(i_argv[1]));
+
+ }
+ else if (strcmp(i_argv[0], "dissect") == 0)
+ {
+
+ openAndMapReadOnly(i_imageFile, &fd, &image, i_maskIgnores);
+#ifdef XIP_TOOL_ENABLE_DISSECT
+ rc = dissectRingSection(image, i_argc - 1, &(i_argv[1]));
+#else
+ fprintf(stderr, "\n");
+ fprintf(stderr, "-------------------------------\n");
+ fprintf(stderr, " dissect feature not supported \n");
+ fprintf(stderr, "-------------------------------\n\n");
+ exit(1);
+#endif
+
+ }
+ else if (strcmp(i_argv[0], "disasm") == 0)
+ {
+
+ //openAndMapReadOnly(i_imageFile, &fd, &image, i_maskIgnores);
+ //rc = disassembleSection(image, i_argc - 1, &(i_argv[1]));
+ fprintf(stderr, "not supported\n");
+ exit(1);
+
+ }
+ else if (strcmp(i_argv[0], "TEST") == 0)
+ {
+
+ openAndMapWritable(i_imageFile, &fd, &image, i_maskIgnores);
+ rc = TEST(image, i_argc - 1, &(i_argv[1]));
+
+ }
+ else
+ {
+ fprintf(stderr, g_usage);
+ exit(1);
+ }
+
+ if (rc)
+ {
+ fprintf(stderr, "Command failed : %s\n",
+ P9_XIP_ERROR_STRING(g_errorStrings, rc));
+ exit(1);
+ }
+}
+
+
+// Open, map and validate the image, then parse and execute the command. The
+// image is memory-mapped read/write, i.e, it may be modified in-place.
+// Commands that modify the size of the image will close and recreate the
+// file.
+
+int
+main(int argc, const char** argv)
+{
+ uint8_t argcMin, idxArgvFlagsStart;
+ uint8_t numFlags = 0, idxArgv, bMoreFlags;
+ uint32_t maskIgnores = 0;
+
+ argcMin = 3;
+ idxArgvFlagsStart = argcMin - 1; // -i flags must start after image file name.
+
+ numFlags = 0;
+ bMoreFlags = 1;
+
+ do
+ {
+ idxArgv = idxArgvFlagsStart + numFlags;
+
+ if (idxArgv <= (argc - 1))
+ {
+ if (strncmp(argv[idxArgv], "-i", 1) == 0)
+ {
+ numFlags++;
+ bMoreFlags = 1;
+
+ if (strncmp(argv[idxArgv], "-ifs", 4) == 0)
+ {
+ maskIgnores = maskIgnores | P9_XIP_IGNORE_FILE_SIZE;
+ }
+ else if (strncmp(argv[idxArgv], "-iv", 3) == 0)
+ {
+ maskIgnores = maskIgnores | P9_XIP_IGNORE_ALL;
+ }
+ else
+ {
+ fprintf(stderr, g_usage);
+ fprintf(stderr, "\n");
+ fprintf(stderr, "argv[%i]=%s is an unsupported flag.", idxArgv, argv[idxArgv]);
+ fprintf(stderr, "See top of above help menu for supported flags.\n");
+ exit(1);
+ }
+ }
+ else
+ {
+ bMoreFlags = 0;
+ }
+ }
+ else
+ {
+ bMoreFlags = 0;
+ break;
+ }
+ }
+ while (bMoreFlags);
+
+ if ((argc < (argcMin + numFlags)) ||
+ (strncmp(argv[1], "-h", 2) == 0) ||
+ (strncmp(argv[1], "--h", 3) == 0) )
+ {
+ fprintf(stderr, g_usage);
+ exit(1);
+ }
+
+ command(argv[1], argc - idxArgv, &(argv[idxArgv]), maskIgnores);
+
+ return 0;
+}
OpenPOWER on IntegriCloud