summaryrefslogtreecommitdiffstats
path: root/src/import/chips/p9/xip
diff options
context:
space:
mode:
authorMartin Peschke <mpeschke@de.ibm.com>2015-11-26 18:09:41 +0100
committerDaniel M. Crowell <dcrowell@us.ibm.com>2016-02-22 11:37:16 -0600
commit28c943d1fbc23645dc3275e03c5c1654d37b01ba (patch)
treed910266dd4f12055f090324a27e6188117857390 /src/import/chips/p9/xip
parenta6e5f208a3d89fc0ddeb280f061c37f99dd0a7f4 (diff)
downloadtalos-hostboot-28c943d1fbc23645dc3275e03c5c1654d37b01ba.tar.gz
talos-hostboot-28c943d1fbc23645dc3275e03c5c1654d37b01ba.zip
P9-XIP image build: initial implementation
This code is supposed to be used for all P9-XIP image build flows, including the ones for the Hardware Image (former Reference Image) and for the SBE IPL Image (located in the ppe repository). It has been derived from SBE-XIP code within the ppe repo (tools/image, sbe/image). This code has been succesfully used to build the SBE IPL image in the ppe repository. This code should is capable of building images, while it does not come with support for putting default values into attributes yet. Changes include: - cut down on number of included header files (eliminating lots of dependencies related to ppe and ekb repos) - a lot of renaming (SBE to P9-XIP) - Makefile cleanup - cleanup of white space damage Todos: - Some files might need to be revisited later, i.e. anything that doesn't come with a p9_xip_ prefix. - We may want to integrate this into ekb build. - The Makefile contains a check for the required compiler version. If the checks fails, manual actions must be taken. For a fully automated build this needs improvement. - The P9-XIP image build code needs to be mirrored to the ppe repo, and the SBE IPL Image build flow should be adapted to used it. - The sbe_default_tool is not included in this port. Change-Id: I6017602fc61787fbb58673bfc2bf046f19526ff4 Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/23004 Tested-by: Jenkins Server Reviewed-by: Martin Peschke <mpeschke@de.ibm.com> Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/24282 Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/import/chips/p9/xip')
-rw-r--r--src/import/chips/p9/xip/p9_xip_image.c3079
-rw-r--r--src/import/chips/p9/xip/p9_xip_image.h1745
2 files changed, 4824 insertions, 0 deletions
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 000000000..d96c8ae07
--- /dev/null
+++ b/src/import/chips/p9/xip/p9_xip_image.c
@@ -0,0 +1,3079 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/xip/p9_xip_image.c $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* EKB Project */
+/* */
+/* COPYRIGHT 2015,2016 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* 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 "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 uint32_t xipRevLe32(const uint32_t i_x);
+
+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,
+ xipRevLe32(toc->iv_id),
+ xipRevLe32(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
+
+
+// Note: For maximum flexibility we provide private versions of
+// endian-conversion routines rather than counting on a system-specific header
+// to provide these.
+
+/// Byte-reverse a 16-bit integer if on a little-endian machine
+
+XIP_STATIC uint16_t
+xipRevLe16(const uint16_t i_x)
+{
+ uint16_t rx;
+
+#ifndef _BIG_ENDIAN
+ uint8_t* pix = (uint8_t*)(&i_x);
+ uint8_t* prx = (uint8_t*)(&rx);
+
+ prx[0] = pix[1];
+ prx[1] = pix[0];
+#else
+ rx = i_x;
+#endif
+
+ return rx;
+}
+
+
+/// Byte-reverse a 32-bit integer if on a little-endian machine
+
+XIP_STATIC uint32_t
+xipRevLe32(const uint32_t i_x)
+{
+ uint32_t rx;
+
+#ifndef _BIG_ENDIAN
+ uint8_t* pix = (uint8_t*)(&i_x);
+ uint8_t* prx = (uint8_t*)(&rx);
+
+ prx[0] = pix[3];
+ prx[1] = pix[2];
+ prx[2] = pix[1];
+ prx[3] = pix[0];
+#else
+ rx = i_x;
+#endif
+
+ return rx;
+}
+
+
+/// Byte-reverse a 64-bit integer if on a little-endian machine
+
+XIP_STATIC uint64_t
+xipRevLe64(const uint64_t i_x)
+{
+ uint64_t rx;
+
+#ifndef _BIG_ENDIAN
+ uint8_t* pix = (uint8_t*)(&i_x);
+ uint8_t* prx = (uint8_t*)(&rx);
+
+ prx[0] = pix[7];
+ prx[1] = pix[6];
+ prx[2] = pix[5];
+ prx[3] = pix[4];
+ prx[4] = pix[3];
+ prx[5] = pix[2];
+ prx[6] = pix[1];
+ prx[7] = pix[0];
+#else
+ rx = i_x;
+#endif
+
+ return rx;
+}
+
+
+/// What is the image link address?
+
+XIP_STATIC uint64_t
+xipLinkAddress(const void* i_image)
+{
+ return xipRevLe64(((P9XipHeader*)i_image)->iv_linkAddress);
+}
+
+
+/// What is the image size?
+
+XIP_STATIC uint32_t
+xipImageSize(const void* i_image)
+{
+ return xipRevLe32(((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 = xipRevLe32(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 xipRevLe64(((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 != 8
+#error This code assumes the P9-XIP header version 8 layout
+#endif
+
+ o_dest->iv_offset = xipRevLe32(i_src->iv_offset);
+ o_dest->iv_size = xipRevLe32(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 != 8
+#error This code assumes the P9-XIP header version 8 layout
+#endif
+
+ o_dest->iv_id = xipRevLe32(i_src->iv_id);
+ o_dest->iv_data = xipRevLe32(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 = xipRevLe32(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 = xipRevLe32(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;
+}
+
+
+/// Get the information required to search the TOC.
+///
+/// All return values are optional.
+
+XIP_STATIC int
+xipGetToc(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 + xipRevLe32(i_a->iv_id),
+ i_strings + xipRevLe32(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 = xipGetToc(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 = xipGetToc(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 + xipRevLe32(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 = xipRevLe32(xipHash32(hostString));
+ (*io_fixedTocEntry)->iv_offset = xipRevLe16(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 %d\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;
+}
+
+
+/// 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 = xipGetToc(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 = xipRevLe32(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 + xipRevLe16(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(entry_offset, iv_entryOffset, 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(%d/%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(%d/%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(%d/%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(%d/%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(%d/%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(%d/%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 = xipGetToc(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_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)
+ {
+ switch (item.iv_type)
+ {
+ case P9_XIP_UINT8:
+ *o_data = *((uint8_t*)(item.iv_imageData));
+ break;
+
+ case P9_XIP_UINT16:
+ *o_data = xipRevLe16(*((uint16_t*)(item.iv_imageData)));
+ break;
+
+ case P9_XIP_UINT32:
+ *o_data = xipRevLe32(*((uint32_t*)(item.iv_imageData)));
+ break;
+
+ case P9_XIP_UINT64:
+ *o_data = xipRevLe64(*((uint64_t*)(item.iv_imageData)));
+ break;
+
+ case P9_XIP_INT8:
+ *o_data = *((int8_t*)(item.iv_imageData));
+ break;
+
+ case P9_XIP_INT16:
+ *o_data = xipRevLe16(*((int16_t*)(item.iv_imageData)));
+ break;
+
+ case P9_XIP_INT32:
+ *o_data = xipRevLe32(*((int32_t*)(item.iv_imageData)));
+ break;
+
+ case P9_XIP_INT64:
+ *o_data = xipRevLe64(*((int64_t*)(item.iv_imageData)));
+ break;
+
+ case P9_XIP_ADDRESS:
+ *o_data = item.iv_address;
+ break;
+
+ default:
+ rc = TRACE_ERROR(P9_XIP_TYPE_ERROR);
+ break;
+ }
+ }
+
+ 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 = xipRevLe16(((uint16_t*)(item.iv_imageData))[i_index]);
+ break;
+
+ case P9_XIP_UINT32:
+ *o_data = xipRevLe32(((uint32_t*)(item.iv_imageData))[i_index]);
+ break;
+
+ case P9_XIP_UINT64:
+ *o_data = xipRevLe64(((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 = xipRevLe16(((int16_t*)(item.iv_imageData))[i_index]);
+ break;
+
+ case P9_XIP_INT32:
+ *o_data = xipRevLe32(((int32_t*)(item.iv_imageData))[i_index]);
+ break;
+
+ case P9_XIP_INT64:
+ *o_data = xipRevLe64(((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 =
+ xipRevLe64(*((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)) = xipRevLe16((uint16_t)i_data);
+ break;
+
+ case P9_XIP_UINT32:
+ *((uint32_t*)(item.iv_imageData)) = xipRevLe32((uint32_t)i_data);
+ break;
+
+ case P9_XIP_UINT64:
+ *((uint64_t*)(item.iv_imageData)) = xipRevLe64((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)) = xipRevLe16((int16_t)i_data);
+ break;
+
+ case P9_XIP_INT32:
+ *((int32_t*)(item.iv_imageData)) = xipRevLe32((int32_t)i_data);
+ break;
+
+ case P9_XIP_INT64:
+ *((int64_t*)(item.iv_imageData)) = xipRevLe64((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] =
+ xipRevLe16((uint16_t)i_data);
+ break;
+
+ case P9_XIP_UINT32:
+ ((uint32_t*)(item.iv_imageData))[i_index] =
+ xipRevLe32((uint32_t)i_data);
+ break;
+
+ case P9_XIP_UINT64:
+ ((uint64_t*)(item.iv_imageData))[i_index] =
+ xipRevLe64((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] =
+ xipRevLe16((uint16_t)i_data);
+ break;
+
+ case P9_XIP_INT32:
+ ((int32_t*)(item.iv_imageData))[i_index] =
+ xipRevLe32((uint32_t)i_data);
+ break;
+
+ case P9_XIP_INT64:
+ ((int64_t*)(item.iv_imageData))[i_index] =
+ xipRevLe64((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)) =
+ xipRevLe64(i_data);
+
+ }
+ while(0);
+
+ return rc;
+}
+
+
+int
+p9_xip_delete_section(void* io_image, const int i_sectionId)
+{
+ int rc, final;
+ P9XipSection section;
+
+ do
+ {
+ rc = xipQuickCheck(io_image, 1);
+
+ if (rc)
+ {
+ break;
+ }
+
+ rc = p9_xip_get_section(io_image, i_sectionId, &section);
+
+ 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.
+
+ if (section.iv_size == 0)
+ {
+ break;
+ }
+
+ rc = xipFinalSection(io_image, &final);
+
+ if (rc)
+ {
+ break;
+ }
+
+ if (final != i_sectionId)
+ {
+ rc = TRACE_ERRORX(P9_XIP_SECTION_ERROR,
+ "Attempt to delete non-final section %d\n",
+ i_sectionId);
+ break;
+ }
+
+ 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;
+}
+
+
+#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 != 8
+#error This code assumes the P9-XIP header version 8 layout
+#endif
+
+ o_dest->iv_magic = xipRevLe64(i_src->iv_magic);
+ o_dest->iv_entryOffset = xipRevLe64(i_src->iv_entryOffset);
+ o_dest->iv_linkAddress = xipRevLe64(i_src->iv_linkAddress);
+
+ for (i = 0; i < 5; 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 = xipRevLe32(i_src->iv_imageSize);
+ o_dest->iv_buildDate = xipRevLe32(i_src->iv_buildDate);
+ o_dest->iv_buildTime = xipRevLe32(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 = xipGetToc(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 000000000..1d65b220a
--- /dev/null
+++ b/src/import/chips/p9/xip/p9_xip_image.h
@@ -0,0 +1,1745 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p9/xip/p9_xip_image.h $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* EKB Project */
+/* */
+/* COPYRIGHT 2015,2016 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* 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
+
+#ifndef __P9_XIP_IMAGE_H
+#define __P9_XIP_IMAGE_H
+
+#include "fapi_sbe_common.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 8
+
+/// \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.
+///
+/// @{
+
+#define P9_XIP_MAGIC 0x58495020 // "XIP "
+#define P9_BASE_MAGIC ULL(0x5849502042415345) // "XIP BASE"
+#define P9_SEEPROM_MAGIC ULL(0x584950205345504d) // "XIP SEPM"
+#define P9_CENTAUR_MAGIC ULL(0x58495020434e5452) // "XIP CNTR"
+
+/// @}
+
+
+/// \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.
+///
+/// @{
+
+// -*- DO NOT REORDER OR EDIT THIS SET OF CONSTANTS WITHOUT ALSO EDITING -*-
+// -*- THE ASSEMBLER LAYOUT IN p9_xip_header.H. -*-
+
+#define P9_XIP_SECTION_HEADER 0
+#define P9_XIP_SECTION_FIXED 1
+#define P9_XIP_SECTION_FIXED_TOC 2
+#define P9_XIP_SECTION_LOADER_TEXT 3
+#define P9_XIP_SECTION_LOADER_DATA 4
+#define P9_XIP_SECTION_TEXT 5
+#define P9_XIP_SECTION_DATA 6
+#define P9_XIP_SECTION_TOC 7
+#define P9_XIP_SECTION_STRINGS 8
+#define P9_XIP_SECTION_BASE 9
+#define P9_XIP_SECTION_BASELOADER 10
+#define P9_XIP_SECTION_OVERLAYS 11
+#define P9_XIP_SECTION_RINGS 12
+#define P9_XIP_SECTION_HBBL 13
+
+#define P9_XIP_SECTIONS 14
+
+/// @}
+
+
+/// \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
+
+/// @}
+
+
+#ifndef __ASSEMBLER__
+
+/// Applications can expand this macro to create an array of section names.
+#define P9_XIP_SECTION_NAMES(var) \
+ const char* var[] = { \
+ ".header", \
+ ".fixed", \
+ ".fixed_toc", \
+ ".loader_text", \
+ ".loader_data", \
+ ".text", \
+ ".data", \
+ ".toc", \
+ ".strings", \
+ ".base", \
+ ".baseloader", \
+ ".overlays", \
+ ".rings", \
+ ".hbbl", \
+ }
+
+/// 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*)))) ? \
+ "Bug : Invalid P9-XIP section name" : var[n])
+
+
+#endif /* __ASSEMBLER__ */
+
+
+/// 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 <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 offset of the P9-XIP entry point from the start of the image
+ uint64_t iv_entryOffset;
+
+ /// The base address used to link the image, as a full relocatable image
+ /// address
+ uint64_t iv_linkAddress;
+
+ /// The entry address of base loader
+ uint64_t iv_entryAddressSBE;
+
+ /// Reserved for future expansion
+ uint64_t iv_reserved64[4];
+
+ //////////////////////////////////////////////////////////////////////
+ // 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[24];
+
+ /// Reserved for future expansion
+ char iv_reservedChar[24];
+
+} 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 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 a section from a P9-XIP image 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 be deleted. See \ref
+/// p9_xip_sections.
+///
+/// This API effectively deletes a section from a P9-XIP image held in host
+/// memory. Unless the requested section \a i_section is already empty, only
+/// the final (highest address offset) section of the image may be deleted.
+/// Deleting the final 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 now-last section is also
+/// removed.
+///
+/// \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, 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);
+
+
+
+// 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
+
+// Note: For maximum flexibility we provide private versions of
+// endian-conversion routines rather than counting on a system-specific header
+// to provide these.
+
+/// Byte-reverse a 16-bit integer if on a little-endian machine
+XIP_STATIC uint16_t
+xipRevLe16(const uint16_t i_x);
+
+/// Byte-reverse a 32-bit integer if on a little-endian machine
+XIP_STATIC uint32_t
+xipRevLe32(const uint32_t i_x);
+
+
+/// Byte-reverse a 64-bit integer if on a little-endian machine
+XIP_STATIC uint64_t
+xipRevLe64(const uint64_t i_x);
+
+/// \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
+
+/// 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", \
+ }
+
+/// 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__
+// *INDENT-OFF*
+
+/// 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 wlll
+/// 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, .xip_string or
+/// .xip_cvs_revision.
+
+ .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
+
+
+/// Allocate and initialize a CVS Revison string in .strings
+///
+/// \param[in] index The string will be stored in the TOC using this index
+/// symbol.
+///
+/// \param[in] string A CVS revision string to be allocated in .strings. CVS
+/// revision strings are formatted by stripping out and only storing the
+/// actual revision number :
+///
+/// \code
+/// "$Revision <n>.<m> $" -> "<n>.<m>"
+/// \endcode
+
+
+ .macro .xip_cvs_revision, index:req, string:req
+
+ .pushsection .strings
+7874647:
+ ..cvs_revision_string "\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
+
+
+/// Edit and allocate a CVS revision string
+///
+/// CVS revision strings are formatted by stripping out and only storing the
+/// actual revision number :
+/// \code
+/// "$Revision <n>.<m> $" -> "<n>.<m>"
+/// \endcode
+
+ .macro ..cvs_revision_string, rev:req
+ .irpc c, \rev
+ .ifnc "\c", "$"
+ .ifnc "\c", "R"
+ .ifnc "\c", "e"
+ .ifnc "\c", "v"
+ .ifnc "\c", "i"
+ .ifnc "\c", "s"
+ .ifnc "\c", "i"
+ .ifnc "\c", "o"
+ .ifnc "\c", "n"
+ .ifnc "\c", ":"
+ .ifnc "\c", " "
+ .ascii "\c"
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endr
+ .byte 0
+ .endm
+
+// *INDENT-ON*
+#endif // __ASSEMBLER__
+
+#endif // __P9_XIP_TOC_H
OpenPOWER on IntegriCloud