From 8fb3f52276fd37466afb34b85a1dbda3c8ee3e9f Mon Sep 17 00:00:00 2001 From: Claus Michael Olsen Date: Thu, 30 Mar 2017 20:20:23 -0500 Subject: H-code ddLevel support - Front-end hooks for user and back-end codes. xip_image.c has been renamed to xip_image.C to take advantage of C++ ability to overload function call arg list to avoid having to introduce additional skinny "xip_dd_get_section" and "xip_dd_append" functions. p9_xip_get_section() and p9_xip_append() APIs have been updated with an additional DD support arg as their last parm. P9XipSection.iv_reserved8[0] converted to iv_ddSupport to enable XIP level knowledge about ddSupport capability of XIP sections. Introduced p9_xip_dd_section_support() that queries a section's iv_ddSupport flag to tell caller true/false about a sections ddLevel support status. Added support in xip_tool.C as follows: - Updated "append" command to accept an optional arg, ddSupport, if section has ddLevel support or not. - Updated "extract" command to accept an optional arg, ddLevel, specifying which ddLevel to extract. - Updated "report" command's listing to show ddLevel support status of sections. Change-Id: I17e1e09d63e894d4f26cb7b324cf10ab784d78a4 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/38666 Tested-by: PPE CI Tested-by: Hostboot CI Tested-by: Jenkins Server Reviewed-by: Jennifer A. Stofer Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/38667 Tested-by: FSP CI Jenkins Reviewed-by: Sachin Gupta --- src/import/chips/p9/xip/p9_xip_image.C | 3211 ++++++++++++++++++++++++++++ src/import/chips/p9/xip/p9_xip_image.c | 3158 --------------------------- src/import/chips/p9/xip/p9_xip_image.h | 52 +- src/import/chips/p9/xip/p9_xip_tool.C | 205 +- src/import/tools/imageProcs/p9_ipl_build.C | 3 +- 5 files changed, 3425 insertions(+), 3204 deletions(-) create mode 100644 src/import/chips/p9/xip/p9_xip_image.C delete mode 100644 src/import/chips/p9/xip/p9_xip_image.c (limited to 'src/import') diff --git a/src/import/chips/p9/xip/p9_xip_image.C b/src/import/chips/p9/xip/p9_xip_image.C new file mode 100644 index 00000000..96e83c67 --- /dev/null +++ b/src/import/chips/p9/xip/p9_xip_image.C @@ -0,0 +1,3211 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/import/chips/p9/xip/p9_xip_image.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +/// \file p9_xip_image.c +/// \brief APIs for validating, normalizing, searching and manipulating +/// P9-XIP images. +/// +/// The background, APIs and implementation details are documented in the +/// document "P9-XIP Binary format" currently available at this link: +/// +/// - https://mcdoc.boeblingen.de.ibm.com/out/out.ViewDocument.php?documentid=2678 +/// +/// \bug The p9_xip_validate() API should be carefully reviewed to ensure +/// that validating even a corrupt image can not lead to a segfault, i.e., to +/// ensure that no memory outside of the putative bounds of the image is ever +/// referenced during validation. + +#include +#ifdef _WIN32 + #include "win32_stdint.h" + #include "endian.h" +#else + #include + #include +#endif +#include +#include +#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 + #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 + +#define F0x016llx "0x%016" PRIx64 +#define F0x012llx "0x%012" PRIx64 + +XIP_STATIC P9_XIP_ERROR_STRINGS(p9_xip_error_strings); + +#define TRACE_ERROR(x) \ + ({ \ + fprintf(stderr, "%s:%d : Returning error code %d : %s" TRACE_NEWLINE, \ + __FILE__, __LINE__, (x), \ + P9_XIP_ERROR_STRING(p9_xip_error_strings, (x))); \ + (x); \ + }) + +#define TRACE_ERRORX(x, ...) \ + ({ \ + TRACE_ERROR(x); \ + fprintf(stderr, ##__VA_ARGS__); \ + (x); \ + }) + +// Uncomment these if required for debugging, otherwise we get warnings from +// GCC as they are not otherwise used. + +#if 0 + +XIP_STATIC P9_XIP_TYPE_STRINGS(type_strings); + +XIP_STATIC void +dumpToc(int index, P9XipToc* toc) +{ + printf("TOC entry %d @ %p\n" + " iv_id = 0x%08x\n" + " iv_data = 0x%08x\n" + " iv_type = %s\n" + " iv_section = 0x%02x\n" + " iv_elements = %d\n", + index, toc, + htobe32(toc->iv_id), + htobe32(toc->iv_data), + P9_XIP_TYPE_STRING(type_strings, toc->iv_type), + toc->iv_section, + toc->iv_elements); +} + +#endif + +#if 0 + +XIP_STATIC void +dumpItem(P9XipItem* item) +{ + printf("P9XipItem @ %p\n" + " iv_toc = %p\n" + " iv_address = " F0x016llx "\n" + " iv_imageData = %p\n" + " iv_id = %s\n" + " iv_type = %s\n" + " iv_elements = %d\n", + item, + item->iv_toc, + item->iv_address, + item->iv_imageData, + item->iv_id, + P9_XIP_TYPE_STRING(type_strings, item->iv_type), + item->iv_elements); + dumpToc(-1, item->iv_toc); +} + +#endif /* 0 */ + +XIP_STATIC void +dumpSectionTable(const void* i_image) +{ + int i, rc; + P9XipSection section; + + printf("Section table dump of image @ %p\n" + " Entry Offset Size\n" + "-------------------------------\n", + i_image); + + for (i = 0; i < P9_XIP_SECTIONS; i++) + { + rc = p9_xip_get_section(i_image, i, §ion); + + if (rc) + { + printf(">>> dumpSectionTable got error at entry %d : %s\n", + i, P9_XIP_ERROR_STRING(p9_xip_error_strings, rc)); + break; + } + + printf("%7d 0x%08x 0x%08x\n", + i, section.iv_offset, section.iv_size); + } +} + +#else + +#define TRACE_ERROR(x) (x) +#define TRACE_ERRORX(x, ...) (x) +#define dumpToc(...) +#define dumpItem(...) +#define dumpSectionTable(...) + +#endif + + +XIP_STATIC uint64_t +xipLinkAddress(const void* i_image) +{ + return htobe64(((P9XipHeader*)i_image)->iv_linkAddress); +} + + +/// What is the image size? + +XIP_STATIC uint32_t +xipImageSize(const void* i_image) +{ + return htobe32(((P9XipHeader*)i_image)->iv_imageSize); +} + + +/// Set the image size + +XIP_STATIC void +xipSetImageSize(void* io_image, const size_t i_size) +{ + ((P9XipHeader*)io_image)->iv_imageSize = htobe32(i_size); +} + + +/// Re-establish the required final alignment + +XIP_STATIC void +xipFinalAlignment(void* io_image) +{ + uint32_t size; + + size = xipImageSize(io_image); + + if ((size % P9_XIP_FINAL_ALIGNMENT) != 0) + { + xipSetImageSize(io_image, + size + (P9_XIP_FINAL_ALIGNMENT - + (size % P9_XIP_FINAL_ALIGNMENT))); + } +} + + +/// Compute a host address from an image address and offset + +XIP_STATIC void* +xipHostAddressFromOffset(const void* i_image, const uint32_t offset) +{ + return (void*)((unsigned long)i_image + offset); +} + + +/// Convert a IMAGE address to a host address + +XIP_STATIC void* +xipImage2Host(const void* i_image, const uint64_t i_imageAddress) +{ + return xipHostAddressFromOffset(i_image, + i_imageAddress - xipLinkAddress(i_image)); +} + + +XIP_STATIC int +xipValidateImageAddress(const void* i_image, + const uint64_t i_imageAddress, + const uint32_t size) +{ + int rc; + + if ((i_imageAddress < xipLinkAddress(i_image)) || + (i_imageAddress > (xipLinkAddress(i_image) + + xipImageSize(i_image) - + size))) + { + rc = TRACE_ERRORX(P9_XIP_INVALID_ARGUMENT, + "The IMAGE address " F0x012llx + " is outside the bounds " + "of the image (" + F0x012llx ":" F0x012llx + ") for %u-byte access.\n", + i_imageAddress, + xipLinkAddress(i_image), + xipLinkAddress(i_image) + xipImageSize(i_image) - 1, + size); + } + else + { + rc = 0; + } + + return rc; +} + + +/// Get the magic number from the image + +XIP_STATIC uint64_t +xipMagic(const void* i_image) +{ + return htobe64(((P9XipHeader*)i_image)->iv_magic); +} + + +/// Get the header version from the image + +XIP_STATIC uint8_t +xipHeaderVersion(const void* i_image) +{ + return ((P9XipHeader*)i_image)->iv_headerVersion; +} + + +/// Has the image been normalized? + +XIP_STATIC uint8_t +xipNormalized(const void* i_image) +{ + return ((P9XipHeader*)i_image)->iv_normalized; +} + + +/// Has the image TOC been sorted? + +XIP_STATIC uint8_t +xipSorted(const void* i_image) +{ + return ((P9XipHeader*)i_image)->iv_tocSorted; +} + + +/// A quick check that the image exists, has the correct magic and header +/// version, and optionally is normalized. + +XIP_STATIC int +xipQuickCheck(const void* i_image, const int i_normalizationRequired) +{ + int rc; + + do + { + rc = 0; + + if (i_image == 0) + { + rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, + "Image pointer is NULL (0)\n"); + break; + } + + if ((xipMagic(i_image) >> 32) != P9_XIP_MAGIC) + { + rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, + "Magic number mismatch; Found " + "" F0x016llx ", expected 0x%08x........\n", + xipMagic(i_image), P9_XIP_MAGIC); + break; + } + + if ((xipHeaderVersion(i_image)) != P9_XIP_HEADER_VERSION) + { + rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, + "Header version mismatch; Expecting %d, " + "found %d\n", + P9_XIP_HEADER_VERSION, + xipHeaderVersion(i_image)); + break; + } + + if (i_normalizationRequired && !xipNormalized(i_image)) + { + rc = TRACE_ERRORX(P9_XIP_NOT_NORMALIZED, + "Image not normalized\n"); + break; + } + } + while(0); + + return rc; +} + + +/// Convert a 32-bit relocatable offset to a full IMAGE 48-bit address + +XIP_STATIC uint64_t +xipFullAddress(const void* i_image, uint32_t offset) +{ + return (xipLinkAddress(i_image) & 0x0000ffff00000000ull) + offset; +} + + +/// Translate a section table entry + +XIP_STATIC void +xipTranslateSection(P9XipSection* o_dest, const P9XipSection* i_src) +{ +#ifndef _BIG_ENDIAN + +#if P9_XIP_HEADER_VERSION != 9 +#error This code assumes the P9-XIP header version 9 layout +#endif + + o_dest->iv_offset = htobe32(i_src->iv_offset); + o_dest->iv_size = htobe32(i_src->iv_size); + o_dest->iv_alignment = i_src->iv_alignment; + o_dest->iv_ddSupport = i_src->iv_ddSupport; + o_dest->iv_reserved8[0] = 0; + o_dest->iv_reserved8[1] = 0; +#else + + if (o_dest != i_src) + { + *o_dest = *i_src; + } + +#endif /* _BIG_ENDIAN */ +} + + +/// Translate a TOC entry + +XIP_STATIC void +xipTranslateToc(P9XipToc* o_dest, P9XipToc* i_src) +{ +#ifndef _BIG_ENDIAN + +#if P9_XIP_HEADER_VERSION != 9 +#error This code assumes the P9-XIP header version 9 layout +#endif + + o_dest->iv_id = htobe32(i_src->iv_id); + o_dest->iv_data = htobe32(i_src->iv_data); + o_dest->iv_type = i_src->iv_type; + o_dest->iv_section = i_src->iv_section; + o_dest->iv_elements = i_src->iv_elements; + o_dest->iv_pad = 0; +#else + + if (o_dest != i_src) + { + *o_dest = *i_src; + } + +#endif /* _BIG_ENDIAN */ +} + + +/// Find the final (highest-address) section of the image + +XIP_STATIC int +xipFinalSection(const void* i_image, int* o_sectionId) +{ + int i, rc, found; + uint32_t offset; + P9XipHeader hostHeader; + + p9_xip_translate_header(&hostHeader, (P9XipHeader*)i_image); + + found = 0; + offset = 0; + *o_sectionId = 0; /* Make GCC -O3 happy */ + + for (i = 0; i < P9_XIP_SECTIONS; i++) + { + if ((hostHeader.iv_section[i].iv_size != 0) && + (hostHeader.iv_section[i].iv_offset >= offset)) + { + *o_sectionId = i; + offset = hostHeader.iv_section[i].iv_offset; + found = 1; + } + } + + if (!found) + { + rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, "The image is empty\n"); + } + else + { + rc = 0; + } + + return rc; +} + + +/// Return a pointer to an image-format section table entry + +XIP_STATIC int +xipGetSectionPointer(const void* i_image, + const int i_sectionId, + P9XipSection** o_imageSection) +{ + int rc; + + if ((i_sectionId < 0) || (i_sectionId >= P9_XIP_SECTIONS)) + { + rc = TRACE_ERROR(P9_XIP_INVALID_ARGUMENT); + } + else + { + *o_imageSection = + &(((P9XipHeader*)i_image)->iv_section[i_sectionId]); + rc = 0; + } + + return rc; +} + + +/// Restore a section table entry from host format to image format. + +XIP_STATIC int +xipPutSection(const void* i_image, + const int i_sectionId, + P9XipSection* i_hostSection) +{ + int rc; + P9XipSection* imageSection; + + rc = xipGetSectionPointer(i_image, i_sectionId, &imageSection); + + if (!rc) + { + xipTranslateSection(imageSection, i_hostSection); + } + + return rc; +} + + +/// Set the offset of a section + +XIP_STATIC int +xipSetSectionOffset(void* io_image, const int i_section, + const uint32_t i_offset) +{ + P9XipSection* section; + int rc; + + rc = xipGetSectionPointer(io_image, i_section, §ion); + + if (!rc) + { + section->iv_offset = htobe32(i_offset); + } + + return rc; +} + + +/// Set the size of a section + +XIP_STATIC int +xipSetSectionSize(void* io_image, const int i_section, const uint32_t i_size) +{ + P9XipSection* section; + int rc; + + rc = xipGetSectionPointer(io_image, i_section, §ion); + + if (!rc) + { + section->iv_size = htobe32(i_size); + } + + return rc; +} + + +/// Translate a IMAGE address in the image to a section and offset + +// We first check to be sure that the IMAGE address is contained in the image, +// using the full 48-bit form. Then we scan the section table to see which +// section contains the address - if none then the image is corrupted. We can +// (must) use the 32-bit offset form of the address here. + +XIP_STATIC int +xipImage2Section(const void* i_image, + const uint64_t i_imageAddress, + int* o_section, + uint32_t* o_offset) +{ + int rc, sectionId; + P9XipSection section; + uint32_t addressOffset; + + do + { + rc = 0; + + if ((i_imageAddress < xipLinkAddress(i_image)) || + (i_imageAddress > + (xipLinkAddress(i_image) + xipImageSize(i_image)))) + { + rc = TRACE_ERRORX(P9_XIP_INVALID_ARGUMENT, + "image2section: The i_imageAddress argument " + "(" F0x016llx ")\nis outside the bounds of the " + "image (" F0x016llx ":" F0x016llx ")\n", + i_imageAddress, + xipLinkAddress(i_image), + xipLinkAddress(i_image) + xipImageSize(i_image)); + break; + } + + addressOffset = (i_imageAddress - xipLinkAddress(i_image)) & 0xffffffff; + + for (sectionId = 0; sectionId < P9_XIP_SECTIONS; sectionId++) + { + rc = p9_xip_get_section(i_image, sectionId, §ion); + + if (rc) + { + rc = TRACE_ERROR(P9_XIP_BUG); /* Can't happen */ + break; + } + + if ((section.iv_size != 0) && + (addressOffset >= section.iv_offset) && + (addressOffset < (section.iv_offset + section.iv_size))) + { + break; + } + } + + if (rc) + { + break; + } + + if (sectionId == P9_XIP_SECTIONS) + { + rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, + "Error processing IMAGE address " F0x016llx ". " + "The address is not mapped in any section.\n" + "A section table dump appears below\n", + i_imageAddress); + dumpSectionTable(i_image); + break; + } + + *o_section = sectionId; + *o_offset = addressOffset - section.iv_offset; + + } + while(0); + + return rc; +} + + +// Delete the last, i.e., final, section of the image. + +XIP_STATIC int +xipDeleteLastSection(void* io_image, + const int i_sectionId) +{ + int rc, final; + P9XipSection section; + + do + { + + xipSetSectionOffset(io_image, i_sectionId, 0); + xipSetSectionSize(io_image, i_sectionId, 0); + + + // For cleanliness we also remove any alignment padding that had been + // appended between the now-last section and the deleted section, then + // re-establish the final alignment. The assumption is that all images + // always have the correct final alignment, so there is no way this + // could overflow a designated buffer space since the image size is + // the same or has been reduced. + + rc = xipFinalSection(io_image, &final); + + if (rc) + { + break; + } + + rc = p9_xip_get_section(io_image, final, §ion); + + if (rc) + { + break; + } + + xipSetImageSize(io_image, section.iv_offset + section.iv_size); + xipFinalAlignment(io_image); + + } + while (0); + + return rc; +} + + +/// Get the information required to search the TOC. +/// +/// All return values are optional. + +int +p9_xip_get_toc(void* i_image, + P9XipToc** o_toc, + size_t* o_entries, + int* o_sorted, + char** o_strings) +{ + int rc; + P9XipSection tocSection, stringsSection; + + do + { + rc = p9_xip_get_section(i_image, P9_XIP_SECTION_TOC, &tocSection); + + if (rc) + { + break; + } + + rc = p9_xip_get_section(i_image, P9_XIP_SECTION_STRINGS, + &stringsSection); + + if (rc) + { + break; + } + + if (o_toc) + { + *o_toc = (P9XipToc*)((uint8_t*)i_image + tocSection.iv_offset); + } + + if (o_entries) + { + *o_entries = tocSection.iv_size / sizeof(P9XipToc); + } + + if (o_sorted) + { + *o_sorted = xipSorted(i_image); + } + + if (o_strings) + { + *o_strings = (char*)i_image + stringsSection.iv_offset; + } + } + while (0); + + return rc; +} + + +/// Compare two normalized TOC entries for sorting. + +XIP_STATIC int +xipCompareToc(const P9XipToc* i_a, const P9XipToc* i_b, + const char* i_strings) +{ + return strcmp(i_strings + htobe32(i_a->iv_id), + i_strings + htobe32(i_b->iv_id)); +} + + +/// Iterative quicksort of the TOC + +// Note: The stack requirement is limited to 256 bytes + minor local storage. + +XIP_STATIC void +xipQuickSort(P9XipToc* io_toc, int i_left, int i_right, + const char* i_strings) +{ + int i, j, left, right, sp; + P9XipToc pivot, temp; + uint32_t stack[64]; + + sp = 0; + stack[sp++] = i_left; + stack[sp++] = i_right; + + while (sp) + { + + right = stack[--sp]; + left = stack[--sp]; + + i = left; + j = right; + + pivot = io_toc[(i + j) / 2]; + + while (i <= j) + { + while (xipCompareToc(&(io_toc[i]), &pivot, i_strings) < 0) + { + i++; + } + + while (xipCompareToc(&(io_toc[j]), &pivot, i_strings) > 0) + { + j--; + } + + if (i <= j) + { + temp = io_toc[i]; + io_toc[i] = io_toc[j]; + io_toc[j] = temp; + i++; + j--; + } + } + + if (left < j) + { + stack[sp++] = left; + stack[sp++] = j; + } + + if (i < right) + { + stack[sp++] = i; + stack[sp++] = right; + } + } +} + + +/// TOC linear search + +XIP_STATIC int +xipLinearSearch(void* i_image, const char* i_id, P9XipToc** o_entry) +{ + int rc; + P9XipToc* imageToc, hostToc; + size_t entries; + char* strings; + + *o_entry = 0; + rc = p9_xip_get_toc(i_image, &imageToc, &entries, 0, &strings); + + if (!rc) + { + for (; entries; entries--, imageToc++) + { + xipTranslateToc(&hostToc, imageToc); + + if (strcmp(i_id, strings + hostToc.iv_id) == 0) + { + break; + } + } + + if (entries) + { + *o_entry = imageToc; + rc = 0; + } + else + { + *o_entry = 0; + rc = TRACE_ERROR(P9_XIP_ITEM_NOT_FOUND); + } + } + + return rc; +} + + +/// A classic binary search of a (presumed) sorted array + +XIP_STATIC int +xipBinarySearch(void* i_image, const char* i_id, P9XipToc** o_entry) +{ + int rc; + P9XipToc* imageToc; + size_t entries; + char* strings; + int sorted, left, right, next, sort; + + do + { + *o_entry = 0; + + rc = p9_xip_get_toc(i_image, &imageToc, &entries, &sorted, &strings); + + if (rc) + { + break; + } + + if (!sorted) + { + rc = TRACE_ERROR(P9_XIP_BUG); + break; + } + + left = 0; + right = entries - 1; + + while (left <= right) + { + next = (left + right) / 2; + sort = strcmp(i_id, strings + htobe32(imageToc[next].iv_id)); + + if (sort == 0) + { + *o_entry = &(imageToc[next]); + break; + } + else if (sort < 0) + { + right = next - 1; + } + else + { + left = next + 1; + } + } + + if (*o_entry == 0) + { + rc = TRACE_ERROR(P9_XIP_ITEM_NOT_FOUND); + break; + } + } + while (0); + + return rc; +} + + +/// Validate a TOC entry as a mapping function +/// +/// The TOC is validated by searching for the entry, which will uncover +/// duplicate entries or problems with sorting/searching. + +XIP_STATIC int +xipValidateTocEntry(void* io_image, const P9XipItem* i_item, void* io_arg) +{ + int rc; + P9XipItem found; + + do + { + rc = p9_xip_find(io_image, i_item->iv_id, &found); + + if (rc) + { + rc = TRACE_ERRORX(rc, "TOC entry for %s not found\n", + i_item->iv_id); + } + else if (found.iv_toc != i_item->iv_toc) + { + rc = TRACE_ERRORX(P9_XIP_TOC_ERROR, + "Duplicate TOC entry for '%s'\n", i_item->iv_id); + } + + break; + } + while (0); + + return rc; +} + + +// This is the FNV-1a hash, used for hashing symbol names in the .fixed +// section into 32-bit hashes for the mini-TOC. + +// According to the authors: + +// "FNV hash algorithms and source code have been released into the public +// domain. The authors of the FNV algorithmm look deliberate steps to disclose +// the algorhtm (sic) in a public forum soon after it was invented. More than +// a year passed after this public disclosure and the authors deliberatly took +// no steps to patent the FNV algorithm. Therefore it is safe to say that the +// FNV authors have no patent claims on the FNV algorithm as published." + +#define FNV_OFFSET_BASIS 2166136261u +#define FNV_PRIME32 16777619u + +uint32_t +xipHash32(const char* s) +{ + uint32_t hash; + + hash = FNV_OFFSET_BASIS; + + while (*s) + { + hash ^= *s++; + hash *= FNV_PRIME32; + } + + return hash; +} + + +// Normalize a TOC entry + +// Normalize the TOC entry by converting relocatable pointers into 32-bit +// offsets from the beginning of the section containing the data. All +// addresses in the TOC are actually 32-bit offsets in the address space named +// in bits 16:31 of the link address of the image. + +XIP_STATIC int +xipNormalizeToc(void* io_image, P9XipToc* io_imageToc, + P9XipHashedToc** io_fixedTocEntry, + size_t* io_fixedEntriesRemaining) +{ + P9XipToc hostToc; + int idSection, dataSection; + uint32_t idOffset, dataOffset; + char* hostString; + int rc; + + do + { + + // Translate the TOC entry to host format. Then locate the + // sections/offsets of the Id string (which must be in .strings) and + // the data. + + xipTranslateToc(&hostToc, io_imageToc); + + hostString = + (char*)xipImage2Host(io_image, + xipFullAddress(io_image, hostToc.iv_id)); + + rc = xipImage2Section(io_image, + xipFullAddress(io_image, hostToc.iv_id), + &idSection, + &idOffset); + + if (rc) + { + break; + } + + if (idSection != P9_XIP_SECTION_STRINGS) + { + rc = TRACE_ERROR(P9_XIP_IMAGE_ERROR); + break; + } + + rc = xipImage2Section(io_image, + xipFullAddress(io_image, hostToc.iv_data), + &dataSection, + &dataOffset); + + if (rc) + { + break; + } + + // Now replace the Id and data pointers with their offsets, and update + // the data section in the TOC entry. + + hostToc.iv_id = idOffset; + hostToc.iv_data = dataOffset; + hostToc.iv_section = dataSection; + + // If this TOC entry is from .fixed, create a new record in .fixed_toc + + if (hostToc.iv_section == P9_XIP_SECTION_FIXED) + { + + if (*io_fixedEntriesRemaining == 0) + { + rc = TRACE_ERRORX(P9_XIP_TOC_ERROR, + "Too many TOC entries for .fixed\n"); + break; + } + + if (hostToc.iv_data != (uint16_t)hostToc.iv_data) + { + rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, + "The .fixed section is too big to index\n"); + break; + } + + (*io_fixedTocEntry)->iv_hash = htobe32(xipHash32(hostString)); + (*io_fixedTocEntry)->iv_offset = htobe16(hostToc.iv_data); + (*io_fixedTocEntry)->iv_type = hostToc.iv_type; + (*io_fixedTocEntry)->iv_elements = hostToc.iv_elements; + + (*io_fixedTocEntry)++; + (*io_fixedEntriesRemaining)--; + } + + // Finally update the TOC entry + + xipTranslateToc(io_imageToc, &hostToc); + + } + while (0); + + return rc; +} + + +// Check for hash collisions in the .fixed mini-TOC. Note that endianness is +// not an issue here, as we're comparing for equality. + +XIP_STATIC int +xipHashCollision(P9XipHashedToc* i_fixedToc, size_t i_entries) +{ + int rc; + size_t i, j; + + rc = 0; + + for (i = 0; i < i_entries; i++) + { + for (j = i + 1; j < i_entries; j++) + { + if (i_fixedToc[i].iv_hash == i_fixedToc[j].iv_hash) + { + rc = TRACE_ERRORX(P9_XIP_HASH_COLLISION, + "Hash collision at index %zd\n", + i); + break; + } + } + + if (rc) + { + break; + } + } + + return rc; +} + + +/// Decode a normalized image-format TOC entry into a host-format P9XipItem +/// structure + +XIP_STATIC int +xipDecodeToc(void* i_image, + P9XipToc* i_imageToc, + P9XipItem* o_item) +{ + int rc; + P9XipToc hostToc; + P9XipSection dataSection, stringsSection; + + do + { + if (!xipNormalized(i_image)) + { + rc = TRACE_ERROR(P9_XIP_NOT_NORMALIZED); + break; + } + + + // Translate the TOC entry and set the TOC pointer, data type and + // number of elements in the outgoing structure. The Id string is + // always located in the TOC_STRINGS section. + + xipTranslateToc(&hostToc, i_imageToc); + + o_item->iv_toc = i_imageToc; + o_item->iv_type = hostToc.iv_type; + o_item->iv_elements = hostToc.iv_elements; + + p9_xip_get_section(i_image, P9_XIP_SECTION_STRINGS, &stringsSection); + o_item->iv_id = + (char*)i_image + stringsSection.iv_offset + hostToc.iv_id; + + + // The data (or text address) are addressed by relative offsets from + // the beginning of their section. The TOC entry may remain in the TOC + // even though the section has been removed from the image, so this + // case needs to be covered. + + rc = p9_xip_get_section(i_image, hostToc.iv_section, &dataSection); + + if (rc) + { + break; + } + + if (dataSection.iv_size == 0) + { + rc = TRACE_ERROR(P9_XIP_DATA_NOT_PRESENT); + break; + } + + o_item->iv_imageData = + (void*)((uint8_t*)i_image + + dataSection.iv_offset + hostToc.iv_data); + + o_item->iv_address = + xipLinkAddress(i_image) + dataSection.iv_offset + hostToc.iv_data; + + o_item->iv_partial = 0; + + } + while (0); + + return rc; +} + +int +p9_xip_decode_toc_dump(void* i_image, void* i_dump, + P9XipToc* i_imageToc, + P9XipItem* o_item) +{ + int rc = 0; + P9XipToc hostToc = {0}; + P9XipSection stringsSection = {0}; + + if (!xipNormalized(i_image)) + { + rc = TRACE_ERROR(P9_XIP_NOT_NORMALIZED); + return rc; + } + + // Translate the TOC entry and set the TOC pointer, data type and + // number of elements in the outgoing structure. The Id string is + // always located in the TOC_STRINGS section. + + xipTranslateToc(&hostToc, i_imageToc); + + o_item->iv_toc = i_imageToc; + o_item->iv_type = hostToc.iv_type; + o_item->iv_elements = hostToc.iv_elements; + + p9_xip_get_section(i_image, P9_XIP_SECTION_STRINGS, &stringsSection); + o_item->iv_id = + (char*)i_image + stringsSection.iv_offset + hostToc.iv_id; + + //Print only the attributes present in fixed section of SEEPROM image + if (hostToc.iv_section == P9_XIP_SECTION_FIXED) + { + //get the attribute value from dump file + o_item->iv_imageData = (void*)((uint8_t*)i_dump + hostToc.iv_data); + o_item->iv_address = xipLinkAddress(i_image) + hostToc.iv_data; + o_item->iv_partial = 0; + } + else + { + o_item->iv_address = 0; + } + + return rc; +} + +/// Sort the TOC + +XIP_STATIC int +xipSortToc(void* io_image) +{ + int rc; + P9XipToc* hostToc; + size_t entries; + char* strings; + + do + { + rc = xipQuickCheck(io_image, 1); + + if (rc) + { + break; + } + + if (xipSorted(io_image)) + { + break; + } + + rc = p9_xip_get_toc(io_image, &hostToc, &entries, 0, &strings); + + if (rc) + { + break; + } + + xipQuickSort(hostToc, 0, entries - 1, strings); + + ((P9XipHeader*)io_image)->iv_tocSorted = 1; + + } + while (0); + + return rc; +} + + +// Pad the image with 0 to a given power-of-2 alignment. The image size is +// modified to reflect the pad, but the caller must modify the section size to +// reflect the pad. + +XIP_STATIC int +xipPadImage(void* io_image, uint32_t i_allocation, + uint32_t i_align, uint32_t* pad) +{ + int rc; + + do + { + rc = 0; + + if ((i_align == 0) || ((i_align & (i_align - 1)) != 0)) + { + rc = TRACE_ERRORX(P9_XIP_INVALID_ARGUMENT, + "Alignment specification (%u) " + "not a power-of-2\n", + i_align); + break; + } + + *pad = xipImageSize(io_image) % i_align; + + if (*pad != 0) + { + *pad = i_align - *pad; + + if ((xipImageSize(io_image) + *pad) > i_allocation) + { + rc = TRACE_ERROR(P9_XIP_WOULD_OVERFLOW); + break; + } + + memset((void*)((unsigned long)io_image + xipImageSize(io_image)), + 0, *pad); + xipSetImageSize(io_image, xipImageSize(io_image) + *pad); + } + } + while (0); + + return rc; +} + + +// Get the .fixed_toc section + +XIP_STATIC int +xipGetFixedToc(void* io_image, + P9XipHashedToc** o_imageToc, + size_t* o_entries) +{ + int rc; + P9XipSection section; + + rc = p9_xip_get_section(io_image, P9_XIP_SECTION_FIXED_TOC, §ion); + + if (!rc) + { + + *o_imageToc = + (P9XipHashedToc*)((unsigned long)io_image + section.iv_offset); + + *o_entries = section.iv_size / sizeof(P9XipHashedToc); + } + + return rc; +} + + +// Search for an item in the fixed TOC, and populate a partial TOC entry if +// requested. This table is small and unsorted so a linear search is +// adequate. The TOC structures are also small so all byte-reversal is done +// 'by hand' rather than with a translate-type API. + +XIP_STATIC int +xipFixedFind(void* i_image, const char* i_id, P9XipItem* o_item) +{ + int rc; + P9XipHashedToc* toc; + size_t entries; + uint32_t hash; + P9XipSection fixedSection; + uint32_t offset; + + do + { + rc = xipGetFixedToc(i_image, &toc, &entries); + + if (rc) + { + break; + } + + for (hash = htobe32(xipHash32(i_id)); entries != 0; entries--, toc++) + { + if (toc->iv_hash == hash) + { + break; + } + } + + if (entries == 0) + { + rc = P9_XIP_ITEM_NOT_FOUND; + break; + } + else + { + rc = 0; + } + + // The caller may have requested a lookup only (o_item == 0), in which + // case we're done. Otherwise we create a partial P9XipItem and + // populate the non-0 fields analogously to the xipDecodeToc() + // routine. The data resides in the .fixed section in this case. + + if (o_item == 0) + { + break; + } + + o_item->iv_partial = 1; + o_item->iv_toc = 0; + o_item->iv_id = 0; + + o_item->iv_type = toc->iv_type; + o_item->iv_elements = toc->iv_elements; + + rc = p9_xip_get_section(i_image, P9_XIP_SECTION_FIXED, &fixedSection); + + if (rc) + { + break; + } + + if (fixedSection.iv_size == 0) + { + rc = TRACE_ERROR(P9_XIP_DATA_NOT_PRESENT); + break; + } + + offset = fixedSection.iv_offset + htobe16(toc->iv_offset); + + o_item->iv_imageData = (void*)((uint8_t*)i_image + offset); + o_item->iv_address = xipLinkAddress(i_image) + offset; + + } + while (0); + + return rc; +} + + +// Search for an item in the special built-in TOC of header fields, and +// populate a partial TOC entry if requested. +// +// This facility was added to allow header data to be searched by name even +// when the TOC has been stripped. This API will only be used in the case of a +// stripped TOC since the header fields are also indexed in the main TOC. +// +// The table is allocated on the stack in order to make this code concurrently +// patchable in PHYP (although PHYP applications will never use this code). +// The table is small and unsorted so a linear search is adequate, and the +// stack requirememts are small. + +XIP_STATIC int +xipHeaderFind(void* i_image, const char* i_id, P9XipItem* o_item) +{ + int rc; + unsigned i; + uint32_t offset; + P9XipSection headerSection; + +#define HEADER_TOC(id, field, type) \ + {#id, offsetof(P9XipHeader, field), type} + + struct HeaderToc + { + + const char* iv_id; + uint16_t iv_offset; + uint8_t iv_type; + + } toc[] = + { + + HEADER_TOC(magic, iv_magic, P9_XIP_UINT64), + HEADER_TOC(link_address, iv_linkAddress, P9_XIP_UINT64), + + HEADER_TOC(image_size, iv_imageSize, P9_XIP_UINT32), + HEADER_TOC(build_date, iv_buildDate, P9_XIP_UINT32), + HEADER_TOC(build_time, iv_buildTime, P9_XIP_UINT32), + HEADER_TOC(build_tag, iv_buildTag, P9_XIP_STRING), + + HEADER_TOC(header_version, iv_headerVersion, P9_XIP_UINT8), + HEADER_TOC(toc_normalized, iv_normalized, P9_XIP_UINT8), + HEADER_TOC(toc_sorted, iv_tocSorted, P9_XIP_UINT8), + + HEADER_TOC(build_user, iv_buildUser, P9_XIP_STRING), + HEADER_TOC(build_host, iv_buildHost, P9_XIP_STRING), + + }; + + do + { + + rc = P9_XIP_ITEM_NOT_FOUND; + + for (i = 0; i < (sizeof(toc) / sizeof(struct HeaderToc)); i++) + { + if (strcmp(i_id, toc[i].iv_id) == 0) + { + rc = 0; + break; + } + } + + if (rc) + { + break; + } + + // The caller may have requested a lookup only (o_item == 0), in which + // case we're done. Otherwise we create a partial P9XipItem and + // populate the non-0 fields analogously to the xipDecodeToc() + // routine. The data resides in the .fixed section in this case. + + if (o_item == 0) + { + break; + } + + o_item->iv_partial = 1; + o_item->iv_toc = 0; + o_item->iv_id = 0; + + o_item->iv_type = toc[i].iv_type; + o_item->iv_elements = 1; /* True for now... */ + + rc = p9_xip_get_section(i_image, P9_XIP_SECTION_HEADER, + &headerSection); + + if (rc) + { + break; + } + + if (headerSection.iv_size == 0) + { + rc = TRACE_ERROR(P9_XIP_DATA_NOT_PRESENT); + break; + } + + offset = headerSection.iv_offset + toc[i].iv_offset; + + o_item->iv_imageData = (void*)((uint8_t*)i_image + offset); + o_item->iv_address = xipLinkAddress(i_image) + offset; + + } + while (0); + + return rc; +} + + +//////////////////////////////////////////////////////////////////////////// +// Published API +//////////////////////////////////////////////////////////////////////////// + +int +p9_xip_validate(void* i_image, const uint32_t i_size) +{ + P9XipHeader hostHeader; + int rc = 0, i; + uint32_t linkAddress, imageSize, extent, offset, size; + uint8_t alignment; + + p9_xip_translate_header(&hostHeader, (P9XipHeader*)i_image); + + do + { + + // Validate C/Assembler constraints. + + if (sizeof(P9XipSection) != SIZE_OF_P9_XIP_SECTION) + { + rc = TRACE_ERRORX(P9_XIP_BUG, + "C/Assembler size mismatch(%ld/%d) " + "for P9XipSection\n", + sizeof(P9XipSection), SIZE_OF_P9_XIP_SECTION); + break; + } + + if (sizeof(P9XipToc) != SIZE_OF_P9_XIP_TOC) + { + rc = TRACE_ERRORX(P9_XIP_BUG, + "C/Assembler size mismatch(%ld/%d) " + "for P9XipToc\n", + sizeof(P9XipToc), SIZE_OF_P9_XIP_TOC); + break; + } + + if (sizeof(P9XipHashedToc) != SIZE_OF_P9_XIP_HASHED_TOC) + { + rc = TRACE_ERRORX(P9_XIP_BUG, + "C/Assembler size mismatch(%ld/%d) " + "for P9XipHashedToc\n", + sizeof(P9XipHashedToc), + SIZE_OF_P9_XIP_HASHED_TOC); + break; + } + + // Validate the image pointer and magic number + + rc = xipQuickCheck(i_image, 0); + + if (rc) + { + break; + } + + // Validate the image size + + linkAddress = hostHeader.iv_linkAddress; + imageSize = hostHeader.iv_imageSize; + extent = linkAddress + imageSize; + + if (imageSize < sizeof(P9XipHeader)) + { + rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, + "p9_xip_validate(%p, %u) : " + "The image size recorded in the image " + "(%u) is smaller than the header size.\n", + i_image, i_size, imageSize); + break; + } + + if (imageSize != i_size) + { + rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, + "p9_xip_validate(%p, %u) : " + "The image size recorded in the image " + "(%u) does not match the i_size parameter.\n", + i_image, i_size, imageSize); + break; + } + + if (extent <= linkAddress) + { + rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, + "p9_xip_validate(%p, %u) : " + "Given the link address (%u) and the " + "image size, the image wraps the address space\n", + i_image, i_size, linkAddress); + break; + } + + if ((imageSize % P9_XIP_FINAL_ALIGNMENT) != 0) + { + rc = TRACE_ERRORX(P9_XIP_ALIGNMENT_ERROR, + "p9_xip_validate(%p, %u) : " + "The image size (%u) is not a multiple of %u\n", + i_image, i_size, imageSize, + P9_XIP_FINAL_ALIGNMENT); + break; + } + + // Validate that all sections appear to be within the image + // bounds, and are aligned correctly. + + for (i = 0; i < P9_XIP_SECTIONS; i++) + { + + offset = hostHeader.iv_section[i].iv_offset; + size = hostHeader.iv_section[i].iv_size; + alignment = hostHeader.iv_section[i].iv_alignment; + + if ((offset > imageSize) || + ((offset + size) > imageSize) || + ((offset + size) < offset)) + { + rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, + "Section %d does not appear to be within " + "the bounds of the image\n" + "offset = %u, size = %u, image size = %u\n", + i, offset, size, imageSize); + break; + } + + if ((offset % alignment) != 0) + { + rc = TRACE_ERRORX(P9_XIP_ALIGNMENT_ERROR, + "Section %d requires %d-byte initial " + "alignment but the section offset is %u\n", + i, alignment, offset); + break; + } + } + + if (rc) + { + break; + } + + // If the TOC exists and the image is normalized, validate each TOC + // entry. + + size = hostHeader.iv_section[P9_XIP_SECTION_TOC].iv_size; + + if (size != 0) + { + if (xipNormalized(i_image)) + { + rc = p9_xip_map_toc(i_image, xipValidateTocEntry, 0); + + if (rc) + { + break; + } + } + } + } + while (0); + + return rc; +} + + +int +p9_xip_validate2(void* i_image, const uint32_t i_size, const uint32_t i_maskIgnores) +{ + P9XipHeader hostHeader; + int rc = 0, i; + uint32_t linkAddress, imageSize, extent, offset, size; + uint8_t alignment; + + p9_xip_translate_header(&hostHeader, (P9XipHeader*)i_image); + + do + { + + // Validate C/Assembler constraints. + + if (sizeof(P9XipSection) != SIZE_OF_P9_XIP_SECTION) + { + rc = TRACE_ERRORX(P9_XIP_BUG, + "C/Assembler size mismatch(%ld/%d) " + "for P9XipSection\n", + sizeof(P9XipSection), SIZE_OF_P9_XIP_SECTION); + break; + } + + if (sizeof(P9XipToc) != SIZE_OF_P9_XIP_TOC) + { + rc = TRACE_ERRORX(P9_XIP_BUG, + "C/Assembler size mismatch(%ld/%d) " + "for P9XipToc\n", + sizeof(P9XipToc), SIZE_OF_P9_XIP_TOC); + break; + } + + if (sizeof(P9XipHashedToc) != SIZE_OF_P9_XIP_HASHED_TOC) + { + rc = TRACE_ERRORX(P9_XIP_BUG, + "C/Assembler size mismatch(%ld/%d) " + "for P9XipHashedToc\n", + sizeof(P9XipHashedToc), + SIZE_OF_P9_XIP_HASHED_TOC); + break; + } + + // Validate the image pointer and magic number + + rc = xipQuickCheck(i_image, 0); + + if (rc) + { + break; + } + + // Validate the image size + + linkAddress = hostHeader.iv_linkAddress; + imageSize = hostHeader.iv_imageSize; + extent = linkAddress + imageSize; + + if (imageSize < sizeof(P9XipHeader)) + { + rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, + "p9_xip_validate2(%p, %u) : " + "The image size recorded in the image " + "(%u) is smaller than the header size.\n", + i_image, i_size, imageSize); + break; + } + + if (imageSize != i_size && !(i_maskIgnores & P9_XIP_IGNORE_FILE_SIZE)) + { + rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, + "p9_xip_validate2(%p, %u) : " + "The image size recorded in the image " + "(%u) does not match the i_size parameter.\n", + i_image, i_size, imageSize); + break; + } + + if (extent <= linkAddress) + { + rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, + "p9_xip_validate2(%p, %u) : " + "Given the link address (%u) and the " + "image size, the image wraps the address space\n", + i_image, i_size, linkAddress); + break; + } + + if ((imageSize % P9_XIP_FINAL_ALIGNMENT) != 0) + { + rc = TRACE_ERRORX(P9_XIP_ALIGNMENT_ERROR, + "p9_xip_validate2(%p, %u) : " + "The image size (%u) is not a multiple of %u\n", + i_image, i_size, imageSize, + P9_XIP_FINAL_ALIGNMENT); + break; + } + + // Validate that all sections appear to be within the image + // bounds, and are aligned correctly. + + for (i = 0; i < P9_XIP_SECTIONS; i++) + { + + offset = hostHeader.iv_section[i].iv_offset; + size = hostHeader.iv_section[i].iv_size; + alignment = hostHeader.iv_section[i].iv_alignment; + + if ((offset > imageSize) || + ((offset + size) > imageSize) || + ((offset + size) < offset)) + { + rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, + "Section %d does not appear to be within " + "the bounds of the image\n" + "offset = %u, size = %u, image size = %u\n", + i, offset, size, imageSize); + break; + } + + if ((offset % alignment) != 0) + { + rc = TRACE_ERRORX(P9_XIP_ALIGNMENT_ERROR, + "Section %d requires %d-byte initial " + "alignment but the section offset is %u\n", + i, alignment, offset); + break; + } + } + + if (rc) + { + break; + } + + // If the TOC exists and the image is normalized, validate each TOC + // entry. + + size = hostHeader.iv_section[P9_XIP_SECTION_TOC].iv_size; + + if (size != 0) + { + if (xipNormalized(i_image)) + { + rc = p9_xip_map_toc(i_image, xipValidateTocEntry, 0); + + if (rc) + { + break; + } + } + } + } + while (0); + + return rc; +} + + +// Normalization: +// +// 1. Normalize the TOC, unless the image is already normalized. The image +// must be marked as normalized before sorting. +// +// 2. Sort the TOC. +// +// 3. Clear the section offsets of any empty sections to make the section +// table reports less confusing. +// +// 4. Clear normalization status on any failure. + +int +p9_xip_normalize(void* io_image) +{ + int rc, i; + P9XipSection section; + P9XipToc* imageToc; + P9XipHashedToc* fixedImageToc; + P9XipHashedToc* fixedTocEntry; + size_t tocEntries, fixedTocEntries, fixedEntriesRemaining; + + do + { + rc = xipQuickCheck(io_image, 0); + + if (rc) + { + break; + } + + if (!xipNormalized(io_image)) + { + + rc = p9_xip_get_toc(io_image, &imageToc, &tocEntries, 0, 0); + + if (rc) + { + break; + } + + rc = xipGetFixedToc(io_image, &fixedImageToc, &fixedTocEntries); + + if (rc) + { + break; + } + + fixedTocEntry = fixedImageToc; + fixedEntriesRemaining = fixedTocEntries; + + for (; tocEntries--; imageToc++) + { + rc = xipNormalizeToc(io_image, imageToc, + &fixedTocEntry, &fixedEntriesRemaining); + + if (rc) + { + break; + } + + } + + if (rc) + { + break; + } + + if (fixedEntriesRemaining != 0) + { + rc = TRACE_ERRORX(P9_XIP_TOC_ERROR, + "Not enough TOC entries for .fixed"); + break; + } + + rc = xipHashCollision(fixedImageToc, fixedTocEntries); + + if (rc) + { + break; + } + + ((P9XipHeader*)io_image)->iv_normalized = 1; + } + + rc = xipSortToc(io_image); + + if (rc) + { + break; + } + + for (i = 0; i < P9_XIP_SECTIONS; i++) + { + rc = p9_xip_get_section(io_image, i, §ion); + + 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; +} + + +#ifdef __PPE__ +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; +} + +#else + +int +p9_xip_get_section(const void* i_image, + const int i_sectionId, + P9XipSection* o_hostSection, + const uint8_t i_ddLevel) +{ + int rc; + P9XipSection* imageSection; + + if (i_ddLevel != P9_XIP_UNDEFINED_DDLEVEL) + { + return P9_XIP_NO_DDLEVEL_SUPPORT; + } + + rc = xipGetSectionPointer(i_image, i_sectionId, &imageSection); + + if (!rc) + { + xipTranslateSection(o_hostSection, imageSection); + } + + return rc; +} +#endif + + +// If the 'big' TOC is not present, search the mini-TOCs that only index the +// .fixed and .header sections. + +int +p9_xip_find(void* i_image, + const char* i_id, + P9XipItem* o_item) +{ + int rc; + P9XipToc* toc; + P9XipItem item, *pitem; + P9XipSection* tocSection; + + do + { + rc = xipQuickCheck(i_image, 1); + + if (rc) + { + break; + } + + rc = xipGetSectionPointer(i_image, P9_XIP_SECTION_TOC, &tocSection); + + if (rc) + { + break; + } + + if (tocSection->iv_size == 0) + { + rc = xipFixedFind(i_image, i_id, o_item); + + if (rc) + { + rc = xipHeaderFind(i_image, i_id, o_item); + } + + break; + } + + if (xipSorted(i_image)) + { + rc = xipBinarySearch(i_image, i_id, &toc); + } + else + { + rc = xipLinearSearch(i_image, i_id, &toc); + } + + if (rc) + { + break; + } + + if (o_item) + { + pitem = o_item; + } + else + { + pitem = &item; + } + + rc = xipDecodeToc(i_image, toc, pitem); + + if (rc) + { + break; + } + + } + while (0); + + return rc; +} + +int +p9_xip_get_item(const P9XipItem* i_item, uint64_t* o_data, uint32_t i_index) +{ + if ((i_item->iv_elements != 0) && (i_index >= i_item->iv_elements)) + { + return TRACE_ERROR(P9_XIP_BOUNDS_ERROR); + } + + switch (i_item->iv_type) + { + case P9_XIP_UINT8: + *o_data = ((uint8_t*)(i_item->iv_imageData))[i_index]; + break; + + case P9_XIP_UINT16: + *o_data = htobe16(((uint16_t*)(i_item->iv_imageData))[i_index]); + break; + + case P9_XIP_UINT32: + *o_data = htobe32(((uint32_t*)(i_item->iv_imageData))[i_index]); + break; + + case P9_XIP_UINT64: + *o_data = htobe64(((uint64_t*)(i_item->iv_imageData))[i_index]); + break; + + case P9_XIP_INT8: + *o_data = ((int8_t*)(i_item->iv_imageData))[i_index]; + break; + + case P9_XIP_INT16: + *o_data = htobe16(((int16_t*)(i_item->iv_imageData))[i_index]); + break; + + case P9_XIP_INT32: + *o_data = htobe32(((int32_t*)(i_item->iv_imageData))[i_index]); + break; + + case P9_XIP_INT64: + *o_data = htobe64(((int64_t*)(i_item->iv_imageData))[i_index]); + break; + + case P9_XIP_ADDRESS: + if (i_index) + { + return TRACE_ERROR(P9_XIP_BOUNDS_ERROR); + } + + *o_data = i_item->iv_address; + break; + + case P9_XIP_STRING: + //Nothing to do in case of string, but making sure rc is valid + break; + + default: + return TRACE_ERROR(P9_XIP_TYPE_ERROR); + break; + } + + return 0; +} + +int +p9_xip_get_element(void* i_image, + const char* i_id, + const uint32_t i_index, + uint64_t* o_data) +{ + int rc; + P9XipItem item; + + rc = p9_xip_find(i_image, i_id, &item); + + if (rc) + { + return rc; + } + + return p9_xip_get_item(&item, o_data, i_index); +} + + +int +p9_xip_get_scalar(void* i_image, const char* i_id, uint64_t* o_data) +{ + return p9_xip_get_element(i_image, i_id, 0, o_data); +} + +int +p9_xip_get_string(void* i_image, const char* i_id, char** o_data) +{ + int rc; + P9XipItem item; + + rc = p9_xip_find(i_image, i_id, &item); + + if (!rc) + { + switch (item.iv_type) + { + case P9_XIP_STRING: + *o_data = (char*)(item.iv_imageData); + break; + + default: + rc = TRACE_ERROR(P9_XIP_TYPE_ERROR); + break; + } + } + + return rc; +} + + +int +p9_xip_read_uint64(const void* i_image, + const uint64_t i_imageAddress, + uint64_t* o_data) +{ + int rc; + + do + { + rc = xipQuickCheck(i_image, 0); + + if (rc) + { + break; + } + + rc = xipValidateImageAddress(i_image, i_imageAddress, 8); + + if (rc) + { + break; + } + + if (i_imageAddress % 8) + { + rc = TRACE_ERROR(P9_XIP_ALIGNMENT_ERROR); + break; + } + + *o_data = + htobe64(*((uint64_t*)xipImage2Host(i_image, i_imageAddress))); + + } + while(0); + + return rc; +} + + +int +p9_xip_set_scalar(void* io_image, const char* i_id, const uint64_t i_data) +{ + int rc; + P9XipItem item; + + rc = p9_xip_find(io_image, i_id, &item); + + if (!rc) + { + switch(item.iv_type) + { + case P9_XIP_UINT8: + *((uint8_t*)(item.iv_imageData)) = (uint8_t)i_data; + break; + + case P9_XIP_UINT16: + *((uint16_t*)(item.iv_imageData)) = htobe16((uint16_t)i_data); + break; + + case P9_XIP_UINT32: + *((uint32_t*)(item.iv_imageData)) = htobe32((uint32_t)i_data); + break; + + case P9_XIP_UINT64: + *((uint64_t*)(item.iv_imageData)) = htobe64((uint64_t)i_data); + break; + + case P9_XIP_INT8: + *((int8_t*)(item.iv_imageData)) = (int8_t)i_data; + break; + + case P9_XIP_INT16: + *((int16_t*)(item.iv_imageData)) = htobe16((int16_t)i_data); + break; + + case P9_XIP_INT32: + *((int32_t*)(item.iv_imageData)) = htobe32((int32_t)i_data); + break; + + case P9_XIP_INT64: + *((int64_t*)(item.iv_imageData)) = htobe64((int64_t)i_data); + break; + + default: + rc = TRACE_ERROR(P9_XIP_TYPE_ERROR); + break; + } + } + + return rc; +} + + +int +p9_xip_set_element(void* i_image, + const char* i_id, + const uint32_t i_index, + const uint64_t i_data) +{ + int rc; + P9XipItem item; + + do + { + rc = p9_xip_find(i_image, i_id, &item); + + if (rc) + { + break; + } + + if ((item.iv_elements != 0) && (i_index >= item.iv_elements)) + { + rc = TRACE_ERROR(P9_XIP_BOUNDS_ERROR); + break; + } + + switch (item.iv_type) + { + case P9_XIP_UINT8: + ((uint8_t*)(item.iv_imageData))[i_index] = (uint8_t)i_data; + break; + + case P9_XIP_UINT16: + ((uint16_t*)(item.iv_imageData))[i_index] = + htobe16((uint16_t)i_data); + break; + + case P9_XIP_UINT32: + ((uint32_t*)(item.iv_imageData))[i_index] = + htobe32((uint32_t)i_data); + break; + + case P9_XIP_UINT64: + ((uint64_t*)(item.iv_imageData))[i_index] = + htobe64((uint64_t)i_data); + break; + + case P9_XIP_INT8: + ((int8_t*)(item.iv_imageData))[i_index] = (int8_t)i_data; + break; + + case P9_XIP_INT16: + ((int16_t*)(item.iv_imageData))[i_index] = + htobe16((uint16_t)i_data); + break; + + case P9_XIP_INT32: + ((int32_t*)(item.iv_imageData))[i_index] = + htobe32((uint32_t)i_data); + break; + + case P9_XIP_INT64: + ((int64_t*)(item.iv_imageData))[i_index] = + htobe64((uint64_t)i_data); + break; + + default: + rc = TRACE_ERROR(P9_XIP_TYPE_ERROR); + break; + } + + if (rc) + { + break; + } + + } + while (0); + + return rc; +} + + +int +p9_xip_set_string(void* i_image, const char* i_id, const char* i_data) +{ + int rc; + P9XipItem item; + char* dest; + + rc = p9_xip_find(i_image, i_id, &item); + + if (!rc) + { + switch (item.iv_type) + { + case P9_XIP_STRING: + dest = (char*)(item.iv_imageData); + + if (strlen(dest) < strlen(i_data)) + { + memcpy(dest, i_data, strlen(dest)); + } + else + { + strcpy(dest, i_data); + } + + break; + + default: + rc = TRACE_ERROR(P9_XIP_TYPE_ERROR); + break; + } + } + + return rc; +} + + +int +p9_xip_write_uint64(void* io_image, + const uint64_t i_imageAddress, + const uint64_t i_data) +{ + int rc; + + do + { + rc = xipQuickCheck(io_image, 0); + + if (rc) + { + break; + } + + rc = xipValidateImageAddress(io_image, i_imageAddress, 8); + + if (rc) + { + break; + } + + if (i_imageAddress % 8) + { + rc = TRACE_ERROR(P9_XIP_ALIGNMENT_ERROR); + break; + } + + *((uint64_t*)xipImage2Host(io_image, i_imageAddress)) = + htobe64(i_data); + + } + while(0); + + return rc; +} + + +int +p9_xip_delete_section(void* io_image, + void* o_imageBuf, + const uint32_t i_imageBufSize, + const int i_sectionId) +{ + int rc, final; + P9XipSection section; + size_t imageSize; + uint8_t bImageChanged = 0; // Tracks if io_image has been modified. + + do + { + + // Get image size. We'll need it a lot. + + imageSize = xipImageSize(io_image); + + // Parm check 1: imageBufSize + // - Must be >=imageSize for a valid imageBuf buffer + + if (i_imageBufSize < imageSize && o_imageBuf != NULL) + { + rc = TRACE_ERRORX(P9_XIP_WOULD_OVERFLOW, + "xip_delete_section(): imageBufSize too small"); + break; + } + + // Parm check 2: sectionId + // - It is illegal to remove the .header. It would kill the image. + + if (i_sectionId == P9_XIP_SECTION_HEADER) + { + rc = TRACE_ERRORX(P9_XIP_SECTION_ERROR, + "xip_delete_section(): It is illegal to remove .header"); + break; + } + + // Copy io_image to o_imageBuf if a valid imageBuf ptr is + // supplied, i.e., imageBuf!=NULL. We'll need a reference copy + // of any delected section to be re-appended after the section + // delete process is done. + if (o_imageBuf != NULL) + { + // We always return a copy of the original input image. + memcpy(o_imageBuf, io_image, imageSize); + } + + // Check the image + + rc = xipQuickCheck(io_image, 1); + + if (rc) + { + break; + } + + // Deleting an empty section is a NOP. Otherwise the section must be + // the final section of the image. Update the sizes and re-establish + // the final image alignment. + + rc = p9_xip_get_section(io_image, i_sectionId, §ion); + + if (rc) + { + break; + } + + if (section.iv_size == 0) + { + break; + } + + // Determine last image section. + + rc = xipFinalSection(io_image, &final); + + if (rc) + { + break; + } + + // Now, delete necessary sections in order of highest section offset + // to the offset of the section, i_sectionId, to be removed. + + if (final == i_sectionId) + { + rc = xipDeleteLastSection(io_image, i_sectionId); + + bImageChanged = 1; + + break; + } + else + { + // Check for imageBuf ptr violation. If this fails, this is + // catastrophic since we don't have a reference copy of the input + // image (i.e, the memcpy of the image earlier wasn't executed.) + + if (o_imageBuf == NULL) + { + rc = TRACE_ERRORX(P9_XIP_NULL_BUFFER, + "xip_delete_section(): Can't copy image into NULL buffer\n"); + break; + } + + // Delete sections, in order, that have offset addresses higher + // than i_sectionId and make a note of the order which is to + // be used when re-appending. Then delete i_sectionId. + + uint8_t sectionOrder[P9_XIP_SECTIONS]; + uint8_t orderIdx = 0; + + do + { + + rc = xipFinalSection(io_image, &final); + + if (rc) + { + break; + } + + // It is illegal to remove .header. It would kill the image. + if (final == P9_XIP_SECTION_HEADER) + { + rc = TRACE_ERRORX(P9_XIP_SECTION_ERROR, + "xip_delete_section(): Code bug: Attempt to remove .header"); + break; + } + + if (final != i_sectionId) + { + sectionOrder[orderIdx] = final; + orderIdx++; + } + + rc = xipDeleteLastSection(io_image, final); + + bImageChanged = 1; + + if (rc) + { + break; + } + + } + while (final != i_sectionId); + + if (rc) + { + break; + } + + // Reappend previously deleted sections in original order + + do + { + + orderIdx--; + rc = p9_xip_get_section(o_imageBuf, sectionOrder[orderIdx], §ion); + + if (rc) + { + break; + } + + rc = p9_xip_append( io_image, + sectionOrder[orderIdx], + (void*)(((uint8_t*)o_imageBuf) + section.iv_offset), + (const uint32_t)section.iv_size, + (const uint32_t)imageSize, + NULL, + section.iv_ddSupport ); + + if (rc) + { + break; + } + + } + while (orderIdx); + + break; + } + + } + while (0); + + // Restore broken input image in case of rc!=0. But only do so if input + // image has changed. + + if (rc && bImageChanged) + { + memcpy(io_image, o_imageBuf, imageSize); + } + + return rc; +} + + +#ifndef PPC_HYP + +// This API is not needed by PHYP procedures, and is elided since PHYP does +// not support malloc(). + +int +p9_xip_duplicate_section(const void* i_image, + const int i_sectionId, + void** o_duplicate, + uint32_t* o_size) +{ + P9XipSection section; + int rc; + + *o_duplicate = 0; + + do + { + rc = xipQuickCheck(i_image, 0); + + if (rc) + { + break; + } + + rc = p9_xip_get_section(i_image, i_sectionId, §ion); + + 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, + uint8_t i_ddSupport) +{ + 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, §ion); + + 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; + + section.iv_ddSupport = i_ddSupport; + + if (xipPutSection(io_image, i_sectionId, §ion) != 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, §ion); + + if (rc) + { + break; + } + + if (section.iv_size == 0) + { + rc = TRACE_ERROR(P9_XIP_SECTION_ERROR); + break; + } + + if (i_offset > (section.iv_offset + section.iv_size)) + { + rc = TRACE_ERROR(P9_XIP_INVALID_ARGUMENT); + break; + } + + *o_imageAddress = xipLinkAddress(i_image) + section.iv_offset + i_offset; + + if (*o_imageAddress % 4) + { + rc = TRACE_ERROR(P9_XIP_ALIGNMENT_ERROR); + break; + } + + } + while(0); + + return rc; +} + + +int +p9_xip_image2section(const void* i_image, + const uint64_t i_imageAddress, + int* i_section, + uint32_t* i_offset) +{ + int rc; + + do + { + rc = xipQuickCheck(i_image, 0); + + if (rc) + { + break; + } + + rc = xipImage2Section(i_image, i_imageAddress, i_section, i_offset); + + } + while(0); + + return rc; +} + + +int +p9_xip_image2host(const void* i_image, + const uint64_t i_imageAddress, + void** o_hostAddress) +{ + int rc; + + do + { + rc = xipQuickCheck(i_image, 0); + + if (rc) + { + break; + } + + if ((i_imageAddress < xipLinkAddress(i_image)) || + (i_imageAddress > + (xipLinkAddress(i_image) + xipImageSize(i_image)))) + { + rc = TRACE_ERROR(P9_XIP_INVALID_ARGUMENT); + break; + } + + *o_hostAddress = + xipHostAddressFromOffset(i_image, + i_imageAddress - xipLinkAddress(i_image)); + } + while(0); + + return rc; +} + + +int +p9_xip_host2image(const void* i_image, + void* i_hostAddress, + uint64_t* o_imageAddress) +{ + int rc; + + do + { + rc = xipQuickCheck(i_image, 0); + + if (rc) + { + break; + } + + if ((i_hostAddress < i_image) || + (i_hostAddress > + xipHostAddressFromOffset(i_image, xipImageSize(i_image)))) + { + rc = TRACE_ERROR(P9_XIP_INVALID_ARGUMENT); + break; + } + + *o_imageAddress = xipLinkAddress(i_image) + + ((unsigned long)i_hostAddress - (unsigned long)i_image); + + if (*o_imageAddress % 4) + { + rc = TRACE_ERROR(P9_XIP_ALIGNMENT_ERROR); + break; + } + } + while(0); + + return rc; +} + + +void +p9_xip_translate_header(P9XipHeader* o_dest, const P9XipHeader* i_src) +{ +#ifndef _BIG_ENDIAN + int i; + P9XipSection* destSection; + const P9XipSection* srcSection; + +#if P9_XIP_HEADER_VERSION != 9 +#error This code assumes the P9-XIP header version 9 layout +#endif + + o_dest->iv_magic = htobe64(i_src->iv_magic); + o_dest->iv_L1LoaderAddr = htobe64(i_src->iv_L1LoaderAddr); + o_dest->iv_L2LoaderAddr = htobe64(i_src->iv_L2LoaderAddr); + o_dest->iv_kernelAddr = htobe64(i_src->iv_kernelAddr); + o_dest->iv_linkAddress = htobe64(i_src->iv_linkAddress); + + memset(o_dest->iv_reserved64, 0, sizeof(i_src->iv_reserved64)); + + for (i = 0, destSection = o_dest->iv_section, + srcSection = i_src->iv_section; + i < P9_XIP_SECTIONS; + i++, destSection++, srcSection++) + { + xipTranslateSection(destSection, srcSection); + } + + o_dest->iv_imageSize = htobe32(i_src->iv_imageSize); + o_dest->iv_buildDate = htobe32(i_src->iv_buildDate); + o_dest->iv_buildTime = htobe32(i_src->iv_buildTime); + memcpy(o_dest->iv_buildTag, i_src->iv_buildTag, + sizeof(i_src->iv_buildTag)); + + o_dest->iv_headerVersion = i_src->iv_headerVersion; + o_dest->iv_normalized = i_src->iv_normalized; + o_dest->iv_tocSorted = i_src->iv_tocSorted; + + memset(o_dest->iv_reserved8, 0, sizeof(i_src->iv_reserved8)); + + memcpy(o_dest->iv_buildUser, i_src->iv_buildUser, + sizeof(i_src->iv_buildUser)); + memcpy(o_dest->iv_buildHost, i_src->iv_buildHost, + sizeof(i_src->iv_buildHost)); + memcpy(o_dest->iv_reservedChar, i_src->iv_reservedChar, + sizeof(i_src->iv_reservedChar)); +#else + + if (o_dest != i_src) + { + *o_dest = *i_src; + } + +#endif /* _BIG_ENDIAN */ +} + + +int +p9_xip_map_toc(void* io_image, + int (*i_fn)(void* io_image, + const P9XipItem* i_item, + void* io_arg), + void* io_arg) +{ + int rc; + P9XipToc* imageToc; + P9XipItem item; + size_t entries; + + do + { + rc = xipQuickCheck(io_image, 0); + + if (rc) + { + break; + } + + rc = p9_xip_get_toc(io_image, &imageToc, &entries, 0, 0); + + if (rc) + { + break; + } + + for (; entries--; imageToc++) + { + rc = xipDecodeToc(io_image, imageToc, &item); + + if (rc) + { + break; + } + + rc = i_fn(io_image, &item, io_arg); + + if (rc) + { + break; + } + } + } + while(0); + + return rc; +} + + +#ifndef __PPE__ +// +// Inform caller if specified sectionId has DD support +// +int p9_xip_dd_section_support(const void* i_image, + const int i_sectionId, + bool& o_bDdSupport) +{ + int rc; + P9XipSection section; + + rc = p9_xip_get_section(i_image, i_sectionId, §ion); + + if (!rc) + { + o_bDdSupport = (bool)section.iv_ddSupport; + } + + return rc; +} +#endif diff --git a/src/import/chips/p9/xip/p9_xip_image.c b/src/import/chips/p9/xip/p9_xip_image.c deleted file mode 100644 index c97a3d02..00000000 --- a/src/import/chips/p9/xip/p9_xip_image.c +++ /dev/null @@ -1,3158 +0,0 @@ -/* IBM_PROLOG_BEGIN_TAG */ -/* This is an automatically generated prolog. */ -/* */ -/* $Source: src/import/chips/p9/xip/p9_xip_image.c $ */ -/* */ -/* OpenPOWER sbe Project */ -/* */ -/* Contributors Listed Below - COPYRIGHT 2015,2017 */ -/* [+] International Business Machines Corp. */ -/* */ -/* */ -/* Licensed under the Apache License, Version 2.0 (the "License"); */ -/* you may not use this file except in compliance with the License. */ -/* You may obtain a copy of the License at */ -/* */ -/* http://www.apache.org/licenses/LICENSE-2.0 */ -/* */ -/* Unless required by applicable law or agreed to in writing, software */ -/* distributed under the License is distributed on an "AS IS" BASIS, */ -/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ -/* implied. See the License for the specific language governing */ -/* permissions and limitations under the License. */ -/* */ -/* IBM_PROLOG_END_TAG */ - -/// \file p9_xip_image.c -/// \brief APIs for validating, normalizing, searching and manipulating -/// P9-XIP images. -/// -/// The background, APIs and implementation details are documented in the -/// document "P9-XIP Binary format" currently available at this link: -/// -/// - https://mcdoc.boeblingen.de.ibm.com/out/out.ViewDocument.php?documentid=2678 -/// -/// \bug The p9_xip_validate() API should be carefully reviewed to ensure -/// that validating even a corrupt image can not lead to a segfault, i.e., to -/// ensure that no memory outside of the putative bounds of the image is ever -/// referenced during validation. - -#include -#ifdef _WIN32 - #include "win32_stdint.h" - #include "endian.h" -#else - #include - #include -#endif -#include -#include -#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 - #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 - -#define F0x016llx "0x%016" PRIx64 -#define F0x012llx "0x%012" PRIx64 - -XIP_STATIC P9_XIP_ERROR_STRINGS(p9_xip_error_strings); - -#define TRACE_ERROR(x) \ - ({ \ - fprintf(stderr, "%s:%d : Returning error code %d : %s" TRACE_NEWLINE, \ - __FILE__, __LINE__, (x), \ - P9_XIP_ERROR_STRING(p9_xip_error_strings, (x))); \ - (x); \ - }) - -#define TRACE_ERRORX(x, ...) \ - ({ \ - TRACE_ERROR(x); \ - fprintf(stderr, ##__VA_ARGS__); \ - (x); \ - }) - -// Uncomment these if required for debugging, otherwise we get warnings from -// GCC as they are not otherwise used. - -#if 0 - -XIP_STATIC P9_XIP_TYPE_STRINGS(type_strings); - -XIP_STATIC void -dumpToc(int index, P9XipToc* toc) -{ - printf("TOC entry %d @ %p\n" - " iv_id = 0x%08x\n" - " iv_data = 0x%08x\n" - " iv_type = %s\n" - " iv_section = 0x%02x\n" - " iv_elements = %d\n", - index, toc, - htobe32(toc->iv_id), - htobe32(toc->iv_data), - P9_XIP_TYPE_STRING(type_strings, toc->iv_type), - toc->iv_section, - toc->iv_elements); -} - -#endif - -#if 0 - -XIP_STATIC void -dumpItem(P9XipItem* item) -{ - printf("P9XipItem @ %p\n" - " iv_toc = %p\n" - " iv_address = " F0x016llx "\n" - " iv_imageData = %p\n" - " iv_id = %s\n" - " iv_type = %s\n" - " iv_elements = %d\n", - item, - item->iv_toc, - item->iv_address, - item->iv_imageData, - item->iv_id, - P9_XIP_TYPE_STRING(type_strings, item->iv_type), - item->iv_elements); - dumpToc(-1, item->iv_toc); -} - -#endif /* 0 */ - -XIP_STATIC void -dumpSectionTable(const void* i_image) -{ - int i, rc; - P9XipSection section; - - printf("Section table dump of image @ %p\n" - " Entry Offset Size\n" - "-------------------------------\n", - i_image); - - for (i = 0; i < P9_XIP_SECTIONS; i++) - { - rc = p9_xip_get_section(i_image, i, §ion); - - if (rc) - { - printf(">>> dumpSectionTable got error at entry %d : %s\n", - i, P9_XIP_ERROR_STRING(p9_xip_error_strings, rc)); - break; - } - - printf("%7d 0x%08x 0x%08x\n", - i, section.iv_offset, section.iv_size); - } -} - -#else - -#define TRACE_ERROR(x) (x) -#define TRACE_ERRORX(x, ...) (x) -#define dumpToc(...) -#define dumpItem(...) -#define dumpSectionTable(...) - -#endif - - -XIP_STATIC uint64_t -xipLinkAddress(const void* i_image) -{ - return htobe64(((P9XipHeader*)i_image)->iv_linkAddress); -} - - -/// What is the image size? - -XIP_STATIC uint32_t -xipImageSize(const void* i_image) -{ - return htobe32(((P9XipHeader*)i_image)->iv_imageSize); -} - - -/// Set the image size - -XIP_STATIC void -xipSetImageSize(void* io_image, const size_t i_size) -{ - ((P9XipHeader*)io_image)->iv_imageSize = htobe32(i_size); -} - - -/// Re-establish the required final alignment - -XIP_STATIC void -xipFinalAlignment(void* io_image) -{ - uint32_t size; - - size = xipImageSize(io_image); - - if ((size % P9_XIP_FINAL_ALIGNMENT) != 0) - { - xipSetImageSize(io_image, - size + (P9_XIP_FINAL_ALIGNMENT - - (size % P9_XIP_FINAL_ALIGNMENT))); - } -} - - -/// Compute a host address from an image address and offset - -XIP_STATIC void* -xipHostAddressFromOffset(const void* i_image, const uint32_t offset) -{ - return (void*)((unsigned long)i_image + offset); -} - - -/// Convert a IMAGE address to a host address - -XIP_STATIC void* -xipImage2Host(const void* i_image, const uint64_t i_imageAddress) -{ - return xipHostAddressFromOffset(i_image, - i_imageAddress - xipLinkAddress(i_image)); -} - - -XIP_STATIC int -xipValidateImageAddress(const void* i_image, - const uint64_t i_imageAddress, - const uint32_t size) -{ - int rc; - - if ((i_imageAddress < xipLinkAddress(i_image)) || - (i_imageAddress > (xipLinkAddress(i_image) + - xipImageSize(i_image) - - size))) - { - rc = TRACE_ERRORX(P9_XIP_INVALID_ARGUMENT, - "The IMAGE address " F0x012llx - " is outside the bounds " - "of the image (" - F0x012llx ":" F0x012llx - ") for %u-byte access.\n", - i_imageAddress, - xipLinkAddress(i_image), - xipLinkAddress(i_image) + xipImageSize(i_image) - 1, - size); - } - else - { - rc = 0; - } - - return rc; -} - - -/// Get the magic number from the image - -XIP_STATIC uint64_t -xipMagic(const void* i_image) -{ - return htobe64(((P9XipHeader*)i_image)->iv_magic); -} - - -/// Get the header version from the image - -XIP_STATIC uint8_t -xipHeaderVersion(const void* i_image) -{ - return ((P9XipHeader*)i_image)->iv_headerVersion; -} - - -/// Has the image been normalized? - -XIP_STATIC uint8_t -xipNormalized(const void* i_image) -{ - return ((P9XipHeader*)i_image)->iv_normalized; -} - - -/// Has the image TOC been sorted? - -XIP_STATIC uint8_t -xipSorted(const void* i_image) -{ - return ((P9XipHeader*)i_image)->iv_tocSorted; -} - - -/// A quick check that the image exists, has the correct magic and header -/// version, and optionally is normalized. - -XIP_STATIC int -xipQuickCheck(const void* i_image, const int i_normalizationRequired) -{ - int rc; - - do - { - rc = 0; - - if (i_image == 0) - { - rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, - "Image pointer is NULL (0)\n"); - break; - } - - if ((xipMagic(i_image) >> 32) != P9_XIP_MAGIC) - { - rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, - "Magic number mismatch; Found " - "" F0x016llx ", expected 0x%08x........\n", - xipMagic(i_image), P9_XIP_MAGIC); - break; - } - - if ((xipHeaderVersion(i_image)) != P9_XIP_HEADER_VERSION) - { - rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, - "Header version mismatch; Expecting %d, " - "found %d\n", - P9_XIP_HEADER_VERSION, - xipHeaderVersion(i_image)); - break; - } - - if (i_normalizationRequired && !xipNormalized(i_image)) - { - rc = TRACE_ERRORX(P9_XIP_NOT_NORMALIZED, - "Image not normalized\n"); - break; - } - } - while(0); - - return rc; -} - - -/// Convert a 32-bit relocatable offset to a full IMAGE 48-bit address - -XIP_STATIC uint64_t -xipFullAddress(const void* i_image, uint32_t offset) -{ - return (xipLinkAddress(i_image) & 0x0000ffff00000000ull) + offset; -} - - -/// Translate a section table entry - -XIP_STATIC void -xipTranslateSection(P9XipSection* o_dest, const P9XipSection* i_src) -{ -#ifndef _BIG_ENDIAN - -#if P9_XIP_HEADER_VERSION != 9 -#error This code assumes the P9-XIP header version 9 layout -#endif - - o_dest->iv_offset = htobe32(i_src->iv_offset); - o_dest->iv_size = htobe32(i_src->iv_size); - o_dest->iv_alignment = i_src->iv_alignment; - o_dest->iv_reserved8[0] = 0; - o_dest->iv_reserved8[1] = 0; - o_dest->iv_reserved8[2] = 0; -#else - - if (o_dest != i_src) - { - *o_dest = *i_src; - } - -#endif /* _BIG_ENDIAN */ -} - - -/// Translate a TOC entry - -XIP_STATIC void -xipTranslateToc(P9XipToc* o_dest, P9XipToc* i_src) -{ -#ifndef _BIG_ENDIAN - -#if P9_XIP_HEADER_VERSION != 9 -#error This code assumes the P9-XIP header version 9 layout -#endif - - o_dest->iv_id = htobe32(i_src->iv_id); - o_dest->iv_data = htobe32(i_src->iv_data); - o_dest->iv_type = i_src->iv_type; - o_dest->iv_section = i_src->iv_section; - o_dest->iv_elements = i_src->iv_elements; - o_dest->iv_pad = 0; -#else - - if (o_dest != i_src) - { - *o_dest = *i_src; - } - -#endif /* _BIG_ENDIAN */ -} - - -/// Find the final (highest-address) section of the image - -XIP_STATIC int -xipFinalSection(const void* i_image, int* o_sectionId) -{ - int i, rc, found; - uint32_t offset; - P9XipHeader hostHeader; - - p9_xip_translate_header(&hostHeader, (P9XipHeader*)i_image); - - found = 0; - offset = 0; - *o_sectionId = 0; /* Make GCC -O3 happy */ - - for (i = 0; i < P9_XIP_SECTIONS; i++) - { - if ((hostHeader.iv_section[i].iv_size != 0) && - (hostHeader.iv_section[i].iv_offset >= offset)) - { - *o_sectionId = i; - offset = hostHeader.iv_section[i].iv_offset; - found = 1; - } - } - - if (!found) - { - rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, "The image is empty\n"); - } - else - { - rc = 0; - } - - return rc; -} - - -/// Return a pointer to an image-format section table entry - -XIP_STATIC int -xipGetSectionPointer(const void* i_image, - const int i_sectionId, - P9XipSection** o_imageSection) -{ - int rc; - - if ((i_sectionId < 0) || (i_sectionId >= P9_XIP_SECTIONS)) - { - rc = TRACE_ERROR(P9_XIP_INVALID_ARGUMENT); - } - else - { - *o_imageSection = - &(((P9XipHeader*)i_image)->iv_section[i_sectionId]); - rc = 0; - } - - return rc; -} - - -/// Restore a section table entry from host format to image format. - -XIP_STATIC int -xipPutSection(const void* i_image, - const int i_sectionId, - P9XipSection* i_hostSection) -{ - int rc; - P9XipSection* imageSection; - - rc = xipGetSectionPointer(i_image, i_sectionId, &imageSection); - - if (!rc) - { - xipTranslateSection(imageSection, i_hostSection); - } - - return rc; -} - - -/// Set the offset of a section - -XIP_STATIC int -xipSetSectionOffset(void* io_image, const int i_section, - const uint32_t i_offset) -{ - P9XipSection* section; - int rc; - - rc = xipGetSectionPointer(io_image, i_section, §ion); - - if (!rc) - { - section->iv_offset = htobe32(i_offset); - } - - return rc; -} - - -/// Set the size of a section - -XIP_STATIC int -xipSetSectionSize(void* io_image, const int i_section, const uint32_t i_size) -{ - P9XipSection* section; - int rc; - - rc = xipGetSectionPointer(io_image, i_section, §ion); - - if (!rc) - { - section->iv_size = htobe32(i_size); - } - - return rc; -} - - -/// Translate a IMAGE address in the image to a section and offset - -// We first check to be sure that the IMAGE address is contained in the image, -// using the full 48-bit form. Then we scan the section table to see which -// section contains the address - if none then the image is corrupted. We can -// (must) use the 32-bit offset form of the address here. - -XIP_STATIC int -xipImage2Section(const void* i_image, - const uint64_t i_imageAddress, - int* o_section, - uint32_t* o_offset) -{ - int rc, sectionId; - P9XipSection section; - uint32_t addressOffset; - - do - { - rc = 0; - - if ((i_imageAddress < xipLinkAddress(i_image)) || - (i_imageAddress > - (xipLinkAddress(i_image) + xipImageSize(i_image)))) - { - rc = TRACE_ERRORX(P9_XIP_INVALID_ARGUMENT, - "image2section: The i_imageAddress argument " - "(" F0x016llx ")\nis outside the bounds of the " - "image (" F0x016llx ":" F0x016llx ")\n", - i_imageAddress, - xipLinkAddress(i_image), - xipLinkAddress(i_image) + xipImageSize(i_image)); - break; - } - - addressOffset = (i_imageAddress - xipLinkAddress(i_image)) & 0xffffffff; - - for (sectionId = 0; sectionId < P9_XIP_SECTIONS; sectionId++) - { - rc = p9_xip_get_section(i_image, sectionId, §ion); - - if (rc) - { - rc = TRACE_ERROR(P9_XIP_BUG); /* Can't happen */ - break; - } - - if ((section.iv_size != 0) && - (addressOffset >= section.iv_offset) && - (addressOffset < (section.iv_offset + section.iv_size))) - { - break; - } - } - - if (rc) - { - break; - } - - if (sectionId == P9_XIP_SECTIONS) - { - rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, - "Error processing IMAGE address " F0x016llx ". " - "The address is not mapped in any section.\n" - "A section table dump appears below\n", - i_imageAddress); - dumpSectionTable(i_image); - break; - } - - *o_section = sectionId; - *o_offset = addressOffset - section.iv_offset; - - } - while(0); - - return rc; -} - - -// Delete the last, i.e., final, section of the image. - -XIP_STATIC int -xipDeleteLastSection(void* io_image, - const int i_sectionId) -{ - int rc, final; - P9XipSection section; - - do - { - - xipSetSectionOffset(io_image, i_sectionId, 0); - xipSetSectionSize(io_image, i_sectionId, 0); - - - // For cleanliness we also remove any alignment padding that had been - // appended between the now-last section and the deleted section, then - // re-establish the final alignment. The assumption is that all images - // always have the correct final alignment, so there is no way this - // could overflow a designated buffer space since the image size is - // the same or has been reduced. - - rc = xipFinalSection(io_image, &final); - - if (rc) - { - break; - } - - rc = p9_xip_get_section(io_image, final, §ion); - - if (rc) - { - break; - } - - xipSetImageSize(io_image, section.iv_offset + section.iv_size); - xipFinalAlignment(io_image); - - } - while (0); - - return rc; -} - - -/// Get the information required to search the TOC. -/// -/// All return values are optional. - -int -p9_xip_get_toc(void* i_image, - P9XipToc** o_toc, - size_t* o_entries, - int* o_sorted, - char** o_strings) -{ - int rc; - P9XipSection tocSection, stringsSection; - - do - { - rc = p9_xip_get_section(i_image, P9_XIP_SECTION_TOC, &tocSection); - - if (rc) - { - break; - } - - rc = p9_xip_get_section(i_image, P9_XIP_SECTION_STRINGS, - &stringsSection); - - if (rc) - { - break; - } - - if (o_toc) - { - *o_toc = (P9XipToc*)((uint8_t*)i_image + tocSection.iv_offset); - } - - if (o_entries) - { - *o_entries = tocSection.iv_size / sizeof(P9XipToc); - } - - if (o_sorted) - { - *o_sorted = xipSorted(i_image); - } - - if (o_strings) - { - *o_strings = (char*)i_image + stringsSection.iv_offset; - } - } - while (0); - - return rc; -} - - -/// Compare two normalized TOC entries for sorting. - -XIP_STATIC int -xipCompareToc(const P9XipToc* i_a, const P9XipToc* i_b, - const char* i_strings) -{ - return strcmp(i_strings + htobe32(i_a->iv_id), - i_strings + htobe32(i_b->iv_id)); -} - - -/// Iterative quicksort of the TOC - -// Note: The stack requirement is limited to 256 bytes + minor local storage. - -XIP_STATIC void -xipQuickSort(P9XipToc* io_toc, int i_left, int i_right, - const char* i_strings) -{ - int i, j, left, right, sp; - P9XipToc pivot, temp; - uint32_t stack[64]; - - sp = 0; - stack[sp++] = i_left; - stack[sp++] = i_right; - - while (sp) - { - - right = stack[--sp]; - left = stack[--sp]; - - i = left; - j = right; - - pivot = io_toc[(i + j) / 2]; - - while (i <= j) - { - while (xipCompareToc(&(io_toc[i]), &pivot, i_strings) < 0) - { - i++; - } - - while (xipCompareToc(&(io_toc[j]), &pivot, i_strings) > 0) - { - j--; - } - - if (i <= j) - { - temp = io_toc[i]; - io_toc[i] = io_toc[j]; - io_toc[j] = temp; - i++; - j--; - } - } - - if (left < j) - { - stack[sp++] = left; - stack[sp++] = j; - } - - if (i < right) - { - stack[sp++] = i; - stack[sp++] = right; - } - } -} - - -/// TOC linear search - -XIP_STATIC int -xipLinearSearch(void* i_image, const char* i_id, P9XipToc** o_entry) -{ - int rc; - P9XipToc* imageToc, hostToc; - size_t entries; - char* strings; - - *o_entry = 0; - rc = p9_xip_get_toc(i_image, &imageToc, &entries, 0, &strings); - - if (!rc) - { - for (; entries; entries--, imageToc++) - { - xipTranslateToc(&hostToc, imageToc); - - if (strcmp(i_id, strings + hostToc.iv_id) == 0) - { - break; - } - } - - if (entries) - { - *o_entry = imageToc; - rc = 0; - } - else - { - *o_entry = 0; - rc = TRACE_ERROR(P9_XIP_ITEM_NOT_FOUND); - } - } - - return rc; -} - - -/// A classic binary search of a (presumed) sorted array - -XIP_STATIC int -xipBinarySearch(void* i_image, const char* i_id, P9XipToc** o_entry) -{ - int rc; - P9XipToc* imageToc; - size_t entries; - char* strings; - int sorted, left, right, next, sort; - - do - { - *o_entry = 0; - - rc = p9_xip_get_toc(i_image, &imageToc, &entries, &sorted, &strings); - - if (rc) - { - break; - } - - if (!sorted) - { - rc = TRACE_ERROR(P9_XIP_BUG); - break; - } - - left = 0; - right = entries - 1; - - while (left <= right) - { - next = (left + right) / 2; - sort = strcmp(i_id, strings + htobe32(imageToc[next].iv_id)); - - if (sort == 0) - { - *o_entry = &(imageToc[next]); - break; - } - else if (sort < 0) - { - right = next - 1; - } - else - { - left = next + 1; - } - } - - if (*o_entry == 0) - { - rc = TRACE_ERROR(P9_XIP_ITEM_NOT_FOUND); - break; - } - } - while (0); - - return rc; -} - - -/// Validate a TOC entry as a mapping function -/// -/// The TOC is validated by searching for the entry, which will uncover -/// duplicate entries or problems with sorting/searching. - -XIP_STATIC int -xipValidateTocEntry(void* io_image, const P9XipItem* i_item, void* io_arg) -{ - int rc; - P9XipItem found; - - do - { - rc = p9_xip_find(io_image, i_item->iv_id, &found); - - if (rc) - { - rc = TRACE_ERRORX(rc, "TOC entry for %s not found\n", - i_item->iv_id); - } - else if (found.iv_toc != i_item->iv_toc) - { - rc = TRACE_ERRORX(P9_XIP_TOC_ERROR, - "Duplicate TOC entry for '%s'\n", i_item->iv_id); - } - - break; - } - while (0); - - return rc; -} - - -// This is the FNV-1a hash, used for hashing symbol names in the .fixed -// section into 32-bit hashes for the mini-TOC. - -// According to the authors: - -// "FNV hash algorithms and source code have been released into the public -// domain. The authors of the FNV algorithmm look deliberate steps to disclose -// the algorhtm (sic) in a public forum soon after it was invented. More than -// a year passed after this public disclosure and the authors deliberatly took -// no steps to patent the FNV algorithm. Therefore it is safe to say that the -// FNV authors have no patent claims on the FNV algorithm as published." - -#define FNV_OFFSET_BASIS 2166136261u -#define FNV_PRIME32 16777619u - -uint32_t -xipHash32(const char* s) -{ - uint32_t hash; - - hash = FNV_OFFSET_BASIS; - - while (*s) - { - hash ^= *s++; - hash *= FNV_PRIME32; - } - - return hash; -} - - -// Normalize a TOC entry - -// Normalize the TOC entry by converting relocatable pointers into 32-bit -// offsets from the beginning of the section containing the data. All -// addresses in the TOC are actually 32-bit offsets in the address space named -// in bits 16:31 of the link address of the image. - -XIP_STATIC int -xipNormalizeToc(void* io_image, P9XipToc* io_imageToc, - P9XipHashedToc** io_fixedTocEntry, - size_t* io_fixedEntriesRemaining) -{ - P9XipToc hostToc; - int idSection, dataSection; - uint32_t idOffset, dataOffset; - char* hostString; - int rc; - - do - { - - // Translate the TOC entry to host format. Then locate the - // sections/offsets of the Id string (which must be in .strings) and - // the data. - - xipTranslateToc(&hostToc, io_imageToc); - - hostString = - (char*)xipImage2Host(io_image, - xipFullAddress(io_image, hostToc.iv_id)); - - rc = xipImage2Section(io_image, - xipFullAddress(io_image, hostToc.iv_id), - &idSection, - &idOffset); - - if (rc) - { - break; - } - - if (idSection != P9_XIP_SECTION_STRINGS) - { - rc = TRACE_ERROR(P9_XIP_IMAGE_ERROR); - break; - } - - rc = xipImage2Section(io_image, - xipFullAddress(io_image, hostToc.iv_data), - &dataSection, - &dataOffset); - - if (rc) - { - break; - } - - // Now replace the Id and data pointers with their offsets, and update - // the data section in the TOC entry. - - hostToc.iv_id = idOffset; - hostToc.iv_data = dataOffset; - hostToc.iv_section = dataSection; - - // If this TOC entry is from .fixed, create a new record in .fixed_toc - - if (hostToc.iv_section == P9_XIP_SECTION_FIXED) - { - - if (*io_fixedEntriesRemaining == 0) - { - rc = TRACE_ERRORX(P9_XIP_TOC_ERROR, - "Too many TOC entries for .fixed\n"); - break; - } - - if (hostToc.iv_data != (uint16_t)hostToc.iv_data) - { - rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, - "The .fixed section is too big to index\n"); - break; - } - - (*io_fixedTocEntry)->iv_hash = htobe32(xipHash32(hostString)); - (*io_fixedTocEntry)->iv_offset = htobe16(hostToc.iv_data); - (*io_fixedTocEntry)->iv_type = hostToc.iv_type; - (*io_fixedTocEntry)->iv_elements = hostToc.iv_elements; - - (*io_fixedTocEntry)++; - (*io_fixedEntriesRemaining)--; - } - - // Finally update the TOC entry - - xipTranslateToc(io_imageToc, &hostToc); - - } - while (0); - - return rc; -} - - -// Check for hash collisions in the .fixed mini-TOC. Note that endianness is -// not an issue here, as we're comparing for equality. - -XIP_STATIC int -xipHashCollision(P9XipHashedToc* i_fixedToc, size_t i_entries) -{ - int rc; - size_t i, j; - - rc = 0; - - for (i = 0; i < i_entries; i++) - { - for (j = i + 1; j < i_entries; j++) - { - if (i_fixedToc[i].iv_hash == i_fixedToc[j].iv_hash) - { - rc = TRACE_ERRORX(P9_XIP_HASH_COLLISION, - "Hash collision at index %zd\n", - i); - break; - } - } - - if (rc) - { - break; - } - } - - return rc; -} - - -/// Decode a normalized image-format TOC entry into a host-format P9XipItem -/// structure - -XIP_STATIC int -xipDecodeToc(void* i_image, - P9XipToc* i_imageToc, - P9XipItem* o_item) -{ - int rc; - P9XipToc hostToc; - P9XipSection dataSection, stringsSection; - - do - { - if (!xipNormalized(i_image)) - { - rc = TRACE_ERROR(P9_XIP_NOT_NORMALIZED); - break; - } - - - // Translate the TOC entry and set the TOC pointer, data type and - // number of elements in the outgoing structure. The Id string is - // always located in the TOC_STRINGS section. - - xipTranslateToc(&hostToc, i_imageToc); - - o_item->iv_toc = i_imageToc; - o_item->iv_type = hostToc.iv_type; - o_item->iv_elements = hostToc.iv_elements; - - p9_xip_get_section(i_image, P9_XIP_SECTION_STRINGS, &stringsSection); - o_item->iv_id = - (char*)i_image + stringsSection.iv_offset + hostToc.iv_id; - - - // The data (or text address) are addressed by relative offsets from - // the beginning of their section. The TOC entry may remain in the TOC - // even though the section has been removed from the image, so this - // case needs to be covered. - - rc = p9_xip_get_section(i_image, hostToc.iv_section, &dataSection); - - if (rc) - { - break; - } - - if (dataSection.iv_size == 0) - { - rc = TRACE_ERROR(P9_XIP_DATA_NOT_PRESENT); - break; - } - - o_item->iv_imageData = - (void*)((uint8_t*)i_image + - dataSection.iv_offset + hostToc.iv_data); - - o_item->iv_address = - xipLinkAddress(i_image) + dataSection.iv_offset + hostToc.iv_data; - - o_item->iv_partial = 0; - - } - while (0); - - return rc; -} - -int -p9_xip_decode_toc_dump(void* i_image, void* i_dump, - P9XipToc* i_imageToc, - P9XipItem* o_item) -{ - int rc = 0; - P9XipToc hostToc = {0}; - P9XipSection stringsSection = {0}; - - if (!xipNormalized(i_image)) - { - rc = TRACE_ERROR(P9_XIP_NOT_NORMALIZED); - return rc; - } - - // Translate the TOC entry and set the TOC pointer, data type and - // number of elements in the outgoing structure. The Id string is - // always located in the TOC_STRINGS section. - - xipTranslateToc(&hostToc, i_imageToc); - - o_item->iv_toc = i_imageToc; - o_item->iv_type = hostToc.iv_type; - o_item->iv_elements = hostToc.iv_elements; - - p9_xip_get_section(i_image, P9_XIP_SECTION_STRINGS, &stringsSection); - o_item->iv_id = - (char*)i_image + stringsSection.iv_offset + hostToc.iv_id; - - //Print only the attributes present in fixed section of SEEPROM image - if (hostToc.iv_section == P9_XIP_SECTION_FIXED) - { - //get the attribute value from dump file - o_item->iv_imageData = (void*)((uint8_t*)i_dump + hostToc.iv_data); - o_item->iv_address = xipLinkAddress(i_image) + hostToc.iv_data; - o_item->iv_partial = 0; - } - else - { - o_item->iv_address = 0; - } - - return rc; -} - -/// Sort the TOC - -XIP_STATIC int -xipSortToc(void* io_image) -{ - int rc; - P9XipToc* hostToc; - size_t entries; - char* strings; - - do - { - rc = xipQuickCheck(io_image, 1); - - if (rc) - { - break; - } - - if (xipSorted(io_image)) - { - break; - } - - rc = p9_xip_get_toc(io_image, &hostToc, &entries, 0, &strings); - - if (rc) - { - break; - } - - xipQuickSort(hostToc, 0, entries - 1, strings); - - ((P9XipHeader*)io_image)->iv_tocSorted = 1; - - } - while (0); - - return rc; -} - - -// Pad the image with 0 to a given power-of-2 alignment. The image size is -// modified to reflect the pad, but the caller must modify the section size to -// reflect the pad. - -XIP_STATIC int -xipPadImage(void* io_image, uint32_t i_allocation, - uint32_t i_align, uint32_t* pad) -{ - int rc; - - do - { - rc = 0; - - if ((i_align == 0) || ((i_align & (i_align - 1)) != 0)) - { - rc = TRACE_ERRORX(P9_XIP_INVALID_ARGUMENT, - "Alignment specification (%u) " - "not a power-of-2\n", - i_align); - break; - } - - *pad = xipImageSize(io_image) % i_align; - - if (*pad != 0) - { - *pad = i_align - *pad; - - if ((xipImageSize(io_image) + *pad) > i_allocation) - { - rc = TRACE_ERROR(P9_XIP_WOULD_OVERFLOW); - break; - } - - memset((void*)((unsigned long)io_image + xipImageSize(io_image)), - 0, *pad); - xipSetImageSize(io_image, xipImageSize(io_image) + *pad); - } - } - while (0); - - return rc; -} - - -// Get the .fixed_toc section - -XIP_STATIC int -xipGetFixedToc(void* io_image, - P9XipHashedToc** o_imageToc, - size_t* o_entries) -{ - int rc; - P9XipSection section; - - rc = p9_xip_get_section(io_image, P9_XIP_SECTION_FIXED_TOC, §ion); - - if (!rc) - { - - *o_imageToc = - (P9XipHashedToc*)((unsigned long)io_image + section.iv_offset); - - *o_entries = section.iv_size / sizeof(P9XipHashedToc); - } - - return rc; -} - - -// Search for an item in the fixed TOC, and populate a partial TOC entry if -// requested. This table is small and unsorted so a linear search is -// adequate. The TOC structures are also small so all byte-reversal is done -// 'by hand' rather than with a translate-type API. - -XIP_STATIC int -xipFixedFind(void* i_image, const char* i_id, P9XipItem* o_item) -{ - int rc; - P9XipHashedToc* toc; - size_t entries; - uint32_t hash; - P9XipSection fixedSection; - uint32_t offset; - - do - { - rc = xipGetFixedToc(i_image, &toc, &entries); - - if (rc) - { - break; - } - - for (hash = htobe32(xipHash32(i_id)); entries != 0; entries--, toc++) - { - if (toc->iv_hash == hash) - { - break; - } - } - - if (entries == 0) - { - rc = P9_XIP_ITEM_NOT_FOUND; - break; - } - else - { - rc = 0; - } - - // The caller may have requested a lookup only (o_item == 0), in which - // case we're done. Otherwise we create a partial P9XipItem and - // populate the non-0 fields analogously to the xipDecodeToc() - // routine. The data resides in the .fixed section in this case. - - if (o_item == 0) - { - break; - } - - o_item->iv_partial = 1; - o_item->iv_toc = 0; - o_item->iv_id = 0; - - o_item->iv_type = toc->iv_type; - o_item->iv_elements = toc->iv_elements; - - rc = p9_xip_get_section(i_image, P9_XIP_SECTION_FIXED, &fixedSection); - - if (rc) - { - break; - } - - if (fixedSection.iv_size == 0) - { - rc = TRACE_ERROR(P9_XIP_DATA_NOT_PRESENT); - break; - } - - offset = fixedSection.iv_offset + htobe16(toc->iv_offset); - - o_item->iv_imageData = (void*)((uint8_t*)i_image + offset); - o_item->iv_address = xipLinkAddress(i_image) + offset; - - } - while (0); - - return rc; -} - - -// Search for an item in the special built-in TOC of header fields, and -// populate a partial TOC entry if requested. -// -// This facility was added to allow header data to be searched by name even -// when the TOC has been stripped. This API will only be used in the case of a -// stripped TOC since the header fields are also indexed in the main TOC. -// -// The table is allocated on the stack in order to make this code concurrently -// patchable in PHYP (although PHYP applications will never use this code). -// The table is small and unsorted so a linear search is adequate, and the -// stack requirememts are small. - -XIP_STATIC int -xipHeaderFind(void* i_image, const char* i_id, P9XipItem* o_item) -{ - int rc; - unsigned i; - uint32_t offset; - P9XipSection headerSection; - -#define HEADER_TOC(id, field, type) \ - {#id, offsetof(P9XipHeader, field), type} - - struct HeaderToc - { - - const char* iv_id; - uint16_t iv_offset; - uint8_t iv_type; - - } toc[] = - { - - HEADER_TOC(magic, iv_magic, P9_XIP_UINT64), - HEADER_TOC(link_address, iv_linkAddress, P9_XIP_UINT64), - - HEADER_TOC(image_size, iv_imageSize, P9_XIP_UINT32), - HEADER_TOC(build_date, iv_buildDate, P9_XIP_UINT32), - HEADER_TOC(build_time, iv_buildTime, P9_XIP_UINT32), - HEADER_TOC(build_tag, iv_buildTag, P9_XIP_STRING), - - HEADER_TOC(header_version, iv_headerVersion, P9_XIP_UINT8), - HEADER_TOC(toc_normalized, iv_normalized, P9_XIP_UINT8), - HEADER_TOC(toc_sorted, iv_tocSorted, P9_XIP_UINT8), - - HEADER_TOC(build_user, iv_buildUser, P9_XIP_STRING), - HEADER_TOC(build_host, iv_buildHost, P9_XIP_STRING), - - }; - - do - { - - rc = P9_XIP_ITEM_NOT_FOUND; - - for (i = 0; i < (sizeof(toc) / sizeof(struct HeaderToc)); i++) - { - if (strcmp(i_id, toc[i].iv_id) == 0) - { - rc = 0; - break; - } - } - - if (rc) - { - break; - } - - // The caller may have requested a lookup only (o_item == 0), in which - // case we're done. Otherwise we create a partial P9XipItem and - // populate the non-0 fields analogously to the xipDecodeToc() - // routine. The data resides in the .fixed section in this case. - - if (o_item == 0) - { - break; - } - - o_item->iv_partial = 1; - o_item->iv_toc = 0; - o_item->iv_id = 0; - - o_item->iv_type = toc[i].iv_type; - o_item->iv_elements = 1; /* True for now... */ - - rc = p9_xip_get_section(i_image, P9_XIP_SECTION_HEADER, - &headerSection); - - if (rc) - { - break; - } - - if (headerSection.iv_size == 0) - { - rc = TRACE_ERROR(P9_XIP_DATA_NOT_PRESENT); - break; - } - - offset = headerSection.iv_offset + toc[i].iv_offset; - - o_item->iv_imageData = (void*)((uint8_t*)i_image + offset); - o_item->iv_address = xipLinkAddress(i_image) + offset; - - } - while (0); - - return rc; -} - - -//////////////////////////////////////////////////////////////////////////// -// Published API -//////////////////////////////////////////////////////////////////////////// - -int -p9_xip_validate(void* i_image, const uint32_t i_size) -{ - P9XipHeader hostHeader; - int rc = 0, i; - uint32_t linkAddress, imageSize, extent, offset, size; - uint8_t alignment; - - p9_xip_translate_header(&hostHeader, (P9XipHeader*)i_image); - - do - { - - // Validate C/Assembler constraints. - - if (sizeof(P9XipSection) != SIZE_OF_P9_XIP_SECTION) - { - rc = TRACE_ERRORX(P9_XIP_BUG, - "C/Assembler size mismatch(%ld/%d) " - "for P9XipSection\n", - sizeof(P9XipSection), SIZE_OF_P9_XIP_SECTION); - break; - } - - if (sizeof(P9XipToc) != SIZE_OF_P9_XIP_TOC) - { - rc = TRACE_ERRORX(P9_XIP_BUG, - "C/Assembler size mismatch(%ld/%d) " - "for P9XipToc\n", - sizeof(P9XipToc), SIZE_OF_P9_XIP_TOC); - break; - } - - if (sizeof(P9XipHashedToc) != SIZE_OF_P9_XIP_HASHED_TOC) - { - rc = TRACE_ERRORX(P9_XIP_BUG, - "C/Assembler size mismatch(%ld/%d) " - "for P9XipHashedToc\n", - sizeof(P9XipHashedToc), - SIZE_OF_P9_XIP_HASHED_TOC); - break; - } - - // Validate the image pointer and magic number - - rc = xipQuickCheck(i_image, 0); - - if (rc) - { - break; - } - - // Validate the image size - - linkAddress = hostHeader.iv_linkAddress; - imageSize = hostHeader.iv_imageSize; - extent = linkAddress + imageSize; - - if (imageSize < sizeof(P9XipHeader)) - { - rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, - "p9_xip_validate(%p, %u) : " - "The image size recorded in the image " - "(%u) is smaller than the header size.\n", - i_image, i_size, imageSize); - break; - } - - if (imageSize != i_size) - { - rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, - "p9_xip_validate(%p, %u) : " - "The image size recorded in the image " - "(%u) does not match the i_size parameter.\n", - i_image, i_size, imageSize); - break; - } - - if (extent <= linkAddress) - { - rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, - "p9_xip_validate(%p, %u) : " - "Given the link address (%u) and the " - "image size, the image wraps the address space\n", - i_image, i_size, linkAddress); - break; - } - - if ((imageSize % P9_XIP_FINAL_ALIGNMENT) != 0) - { - rc = TRACE_ERRORX(P9_XIP_ALIGNMENT_ERROR, - "p9_xip_validate(%p, %u) : " - "The image size (%u) is not a multiple of %u\n", - i_image, i_size, imageSize, - P9_XIP_FINAL_ALIGNMENT); - break; - } - - // Validate that all sections appear to be within the image - // bounds, and are aligned correctly. - - for (i = 0; i < P9_XIP_SECTIONS; i++) - { - - offset = hostHeader.iv_section[i].iv_offset; - size = hostHeader.iv_section[i].iv_size; - alignment = hostHeader.iv_section[i].iv_alignment; - - if ((offset > imageSize) || - ((offset + size) > imageSize) || - ((offset + size) < offset)) - { - rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, - "Section %d does not appear to be within " - "the bounds of the image\n" - "offset = %u, size = %u, image size = %u\n", - i, offset, size, imageSize); - break; - } - - if ((offset % alignment) != 0) - { - rc = TRACE_ERRORX(P9_XIP_ALIGNMENT_ERROR, - "Section %d requires %d-byte initial " - "alignment but the section offset is %u\n", - i, alignment, offset); - break; - } - } - - if (rc) - { - break; - } - - // If the TOC exists and the image is normalized, validate each TOC - // entry. - - size = hostHeader.iv_section[P9_XIP_SECTION_TOC].iv_size; - - if (size != 0) - { - if (xipNormalized(i_image)) - { - rc = p9_xip_map_toc(i_image, xipValidateTocEntry, 0); - - if (rc) - { - break; - } - } - } - } - while (0); - - return rc; -} - - -int -p9_xip_validate2(void* i_image, const uint32_t i_size, const uint32_t i_maskIgnores) -{ - P9XipHeader hostHeader; - int rc = 0, i; - uint32_t linkAddress, imageSize, extent, offset, size; - uint8_t alignment; - - p9_xip_translate_header(&hostHeader, (P9XipHeader*)i_image); - - do - { - - // Validate C/Assembler constraints. - - if (sizeof(P9XipSection) != SIZE_OF_P9_XIP_SECTION) - { - rc = TRACE_ERRORX(P9_XIP_BUG, - "C/Assembler size mismatch(%ld/%d) " - "for P9XipSection\n", - sizeof(P9XipSection), SIZE_OF_P9_XIP_SECTION); - break; - } - - if (sizeof(P9XipToc) != SIZE_OF_P9_XIP_TOC) - { - rc = TRACE_ERRORX(P9_XIP_BUG, - "C/Assembler size mismatch(%ld/%d) " - "for P9XipToc\n", - sizeof(P9XipToc), SIZE_OF_P9_XIP_TOC); - break; - } - - if (sizeof(P9XipHashedToc) != SIZE_OF_P9_XIP_HASHED_TOC) - { - rc = TRACE_ERRORX(P9_XIP_BUG, - "C/Assembler size mismatch(%ld/%d) " - "for P9XipHashedToc\n", - sizeof(P9XipHashedToc), - SIZE_OF_P9_XIP_HASHED_TOC); - break; - } - - // Validate the image pointer and magic number - - rc = xipQuickCheck(i_image, 0); - - if (rc) - { - break; - } - - // Validate the image size - - linkAddress = hostHeader.iv_linkAddress; - imageSize = hostHeader.iv_imageSize; - extent = linkAddress + imageSize; - - if (imageSize < sizeof(P9XipHeader)) - { - rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, - "p9_xip_validate2(%p, %u) : " - "The image size recorded in the image " - "(%u) is smaller than the header size.\n", - i_image, i_size, imageSize); - break; - } - - if (imageSize != i_size && !(i_maskIgnores & P9_XIP_IGNORE_FILE_SIZE)) - { - rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, - "p9_xip_validate2(%p, %u) : " - "The image size recorded in the image " - "(%u) does not match the i_size parameter.\n", - i_image, i_size, imageSize); - break; - } - - if (extent <= linkAddress) - { - rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, - "p9_xip_validate2(%p, %u) : " - "Given the link address (%u) and the " - "image size, the image wraps the address space\n", - i_image, i_size, linkAddress); - break; - } - - if ((imageSize % P9_XIP_FINAL_ALIGNMENT) != 0) - { - rc = TRACE_ERRORX(P9_XIP_ALIGNMENT_ERROR, - "p9_xip_validate2(%p, %u) : " - "The image size (%u) is not a multiple of %u\n", - i_image, i_size, imageSize, - P9_XIP_FINAL_ALIGNMENT); - break; - } - - // Validate that all sections appear to be within the image - // bounds, and are aligned correctly. - - for (i = 0; i < P9_XIP_SECTIONS; i++) - { - - offset = hostHeader.iv_section[i].iv_offset; - size = hostHeader.iv_section[i].iv_size; - alignment = hostHeader.iv_section[i].iv_alignment; - - if ((offset > imageSize) || - ((offset + size) > imageSize) || - ((offset + size) < offset)) - { - rc = TRACE_ERRORX(P9_XIP_IMAGE_ERROR, - "Section %d does not appear to be within " - "the bounds of the image\n" - "offset = %u, size = %u, image size = %u\n", - i, offset, size, imageSize); - break; - } - - if ((offset % alignment) != 0) - { - rc = TRACE_ERRORX(P9_XIP_ALIGNMENT_ERROR, - "Section %d requires %d-byte initial " - "alignment but the section offset is %u\n", - i, alignment, offset); - break; - } - } - - if (rc) - { - break; - } - - // If the TOC exists and the image is normalized, validate each TOC - // entry. - - size = hostHeader.iv_section[P9_XIP_SECTION_TOC].iv_size; - - if (size != 0) - { - if (xipNormalized(i_image)) - { - rc = p9_xip_map_toc(i_image, xipValidateTocEntry, 0); - - if (rc) - { - break; - } - } - } - } - while (0); - - return rc; -} - - -// Normalization: -// -// 1. Normalize the TOC, unless the image is already normalized. The image -// must be marked as normalized before sorting. -// -// 2. Sort the TOC. -// -// 3. Clear the section offsets of any empty sections to make the section -// table reports less confusing. -// -// 4. Clear normalization status on any failure. - -int -p9_xip_normalize(void* io_image) -{ - int rc, i; - P9XipSection section; - P9XipToc* imageToc; - P9XipHashedToc* fixedImageToc; - P9XipHashedToc* fixedTocEntry; - size_t tocEntries, fixedTocEntries, fixedEntriesRemaining; - - do - { - rc = xipQuickCheck(io_image, 0); - - if (rc) - { - break; - } - - if (!xipNormalized(io_image)) - { - - rc = p9_xip_get_toc(io_image, &imageToc, &tocEntries, 0, 0); - - if (rc) - { - break; - } - - rc = xipGetFixedToc(io_image, &fixedImageToc, &fixedTocEntries); - - if (rc) - { - break; - } - - fixedTocEntry = fixedImageToc; - fixedEntriesRemaining = fixedTocEntries; - - for (; tocEntries--; imageToc++) - { - rc = xipNormalizeToc(io_image, imageToc, - &fixedTocEntry, &fixedEntriesRemaining); - - if (rc) - { - break; - } - - } - - if (rc) - { - break; - } - - if (fixedEntriesRemaining != 0) - { - rc = TRACE_ERRORX(P9_XIP_TOC_ERROR, - "Not enough TOC entries for .fixed"); - break; - } - - rc = xipHashCollision(fixedImageToc, fixedTocEntries); - - if (rc) - { - break; - } - - ((P9XipHeader*)io_image)->iv_normalized = 1; - } - - rc = xipSortToc(io_image); - - if (rc) - { - break; - } - - for (i = 0; i < P9_XIP_SECTIONS; i++) - { - rc = p9_xip_get_section(io_image, i, §ion); - - if (rc) - { - break; - } - - if (section.iv_size == 0) - { - xipSetSectionOffset(io_image, i, 0); - } - } - - if (rc) - { - break; - } - - } - while(0); - - ((P9XipHeader*)io_image)->iv_normalized = (rc == 0); - - return rc; -} - - -int -p9_xip_image_size(void* io_image, uint32_t* o_size) -{ - int rc; - - rc = xipQuickCheck(io_image, 0); - - if (!rc) - { - *o_size = xipImageSize(io_image); - } - - return rc; -} - - -int -p9_xip_get_section(const void* i_image, - const int i_sectionId, - P9XipSection* o_hostSection) -{ - int rc; - P9XipSection* imageSection; - - rc = xipGetSectionPointer(i_image, i_sectionId, &imageSection); - - if (!rc) - { - xipTranslateSection(o_hostSection, imageSection); - } - - return rc; -} - - -// If the 'big' TOC is not present, search the mini-TOCs that only index the -// .fixed and .header sections. - -int -p9_xip_find(void* i_image, - const char* i_id, - P9XipItem* o_item) -{ - int rc; - P9XipToc* toc; - P9XipItem item, *pitem; - P9XipSection* tocSection; - - do - { - rc = xipQuickCheck(i_image, 1); - - if (rc) - { - break; - } - - rc = xipGetSectionPointer(i_image, P9_XIP_SECTION_TOC, &tocSection); - - if (rc) - { - break; - } - - if (tocSection->iv_size == 0) - { - rc = xipFixedFind(i_image, i_id, o_item); - - if (rc) - { - rc = xipHeaderFind(i_image, i_id, o_item); - } - - break; - } - - if (xipSorted(i_image)) - { - rc = xipBinarySearch(i_image, i_id, &toc); - } - else - { - rc = xipLinearSearch(i_image, i_id, &toc); - } - - if (rc) - { - break; - } - - if (o_item) - { - pitem = o_item; - } - else - { - pitem = &item; - } - - rc = xipDecodeToc(i_image, toc, pitem); - - if (rc) - { - break; - } - - } - while (0); - - return rc; -} - -int -p9_xip_get_item(const P9XipItem* i_item, uint64_t* o_data, uint32_t i_index) -{ - if ((i_item->iv_elements != 0) && (i_index >= i_item->iv_elements)) - { - return TRACE_ERROR(P9_XIP_BOUNDS_ERROR); - } - - switch (i_item->iv_type) - { - case P9_XIP_UINT8: - *o_data = ((uint8_t*)(i_item->iv_imageData))[i_index]; - break; - - case P9_XIP_UINT16: - *o_data = htobe16(((uint16_t*)(i_item->iv_imageData))[i_index]); - break; - - case P9_XIP_UINT32: - *o_data = htobe32(((uint32_t*)(i_item->iv_imageData))[i_index]); - break; - - case P9_XIP_UINT64: - *o_data = htobe64(((uint64_t*)(i_item->iv_imageData))[i_index]); - break; - - case P9_XIP_INT8: - *o_data = ((int8_t*)(i_item->iv_imageData))[i_index]; - break; - - case P9_XIP_INT16: - *o_data = htobe16(((int16_t*)(i_item->iv_imageData))[i_index]); - break; - - case P9_XIP_INT32: - *o_data = htobe32(((int32_t*)(i_item->iv_imageData))[i_index]); - break; - - case P9_XIP_INT64: - *o_data = htobe64(((int64_t*)(i_item->iv_imageData))[i_index]); - break; - - case P9_XIP_ADDRESS: - if (i_index) - { - return TRACE_ERROR(P9_XIP_BOUNDS_ERROR); - } - - *o_data = i_item->iv_address; - break; - - case P9_XIP_STRING: - //Nothing to do in case of string, but making sure rc is valid - break; - - default: - return TRACE_ERROR(P9_XIP_TYPE_ERROR); - break; - } - - return 0; -} - -int -p9_xip_get_element(void* i_image, - const char* i_id, - const uint32_t i_index, - uint64_t* o_data) -{ - int rc; - P9XipItem item; - - rc = p9_xip_find(i_image, i_id, &item); - - if (rc) - { - return rc; - } - - return p9_xip_get_item(&item, o_data, i_index); -} - - -int -p9_xip_get_scalar(void* i_image, const char* i_id, uint64_t* o_data) -{ - return p9_xip_get_element(i_image, i_id, 0, o_data); -} - -int -p9_xip_get_string(void* i_image, const char* i_id, char** o_data) -{ - int rc; - P9XipItem item; - - rc = p9_xip_find(i_image, i_id, &item); - - if (!rc) - { - switch (item.iv_type) - { - case P9_XIP_STRING: - *o_data = (char*)(item.iv_imageData); - break; - - default: - rc = TRACE_ERROR(P9_XIP_TYPE_ERROR); - break; - } - } - - return rc; -} - - -int -p9_xip_read_uint64(const void* i_image, - const uint64_t i_imageAddress, - uint64_t* o_data) -{ - int rc; - - do - { - rc = xipQuickCheck(i_image, 0); - - if (rc) - { - break; - } - - rc = xipValidateImageAddress(i_image, i_imageAddress, 8); - - if (rc) - { - break; - } - - if (i_imageAddress % 8) - { - rc = TRACE_ERROR(P9_XIP_ALIGNMENT_ERROR); - break; - } - - *o_data = - htobe64(*((uint64_t*)xipImage2Host(i_image, i_imageAddress))); - - } - while(0); - - return rc; -} - - -int -p9_xip_set_scalar(void* io_image, const char* i_id, const uint64_t i_data) -{ - int rc; - P9XipItem item; - - rc = p9_xip_find(io_image, i_id, &item); - - if (!rc) - { - switch(item.iv_type) - { - case P9_XIP_UINT8: - *((uint8_t*)(item.iv_imageData)) = (uint8_t)i_data; - break; - - case P9_XIP_UINT16: - *((uint16_t*)(item.iv_imageData)) = htobe16((uint16_t)i_data); - break; - - case P9_XIP_UINT32: - *((uint32_t*)(item.iv_imageData)) = htobe32((uint32_t)i_data); - break; - - case P9_XIP_UINT64: - *((uint64_t*)(item.iv_imageData)) = htobe64((uint64_t)i_data); - break; - - case P9_XIP_INT8: - *((int8_t*)(item.iv_imageData)) = (int8_t)i_data; - break; - - case P9_XIP_INT16: - *((int16_t*)(item.iv_imageData)) = htobe16((int16_t)i_data); - break; - - case P9_XIP_INT32: - *((int32_t*)(item.iv_imageData)) = htobe32((int32_t)i_data); - break; - - case P9_XIP_INT64: - *((int64_t*)(item.iv_imageData)) = htobe64((int64_t)i_data); - break; - - default: - rc = TRACE_ERROR(P9_XIP_TYPE_ERROR); - break; - } - } - - return rc; -} - - -int -p9_xip_set_element(void* i_image, - const char* i_id, - const uint32_t i_index, - const uint64_t i_data) -{ - int rc; - P9XipItem item; - - do - { - rc = p9_xip_find(i_image, i_id, &item); - - if (rc) - { - break; - } - - if ((item.iv_elements != 0) && (i_index >= item.iv_elements)) - { - rc = TRACE_ERROR(P9_XIP_BOUNDS_ERROR); - break; - } - - switch (item.iv_type) - { - case P9_XIP_UINT8: - ((uint8_t*)(item.iv_imageData))[i_index] = (uint8_t)i_data; - break; - - case P9_XIP_UINT16: - ((uint16_t*)(item.iv_imageData))[i_index] = - htobe16((uint16_t)i_data); - break; - - case P9_XIP_UINT32: - ((uint32_t*)(item.iv_imageData))[i_index] = - htobe32((uint32_t)i_data); - break; - - case P9_XIP_UINT64: - ((uint64_t*)(item.iv_imageData))[i_index] = - htobe64((uint64_t)i_data); - break; - - case P9_XIP_INT8: - ((int8_t*)(item.iv_imageData))[i_index] = (int8_t)i_data; - break; - - case P9_XIP_INT16: - ((int16_t*)(item.iv_imageData))[i_index] = - htobe16((uint16_t)i_data); - break; - - case P9_XIP_INT32: - ((int32_t*)(item.iv_imageData))[i_index] = - htobe32((uint32_t)i_data); - break; - - case P9_XIP_INT64: - ((int64_t*)(item.iv_imageData))[i_index] = - htobe64((uint64_t)i_data); - break; - - default: - rc = TRACE_ERROR(P9_XIP_TYPE_ERROR); - break; - } - - if (rc) - { - break; - } - - } - while (0); - - return rc; -} - - -int -p9_xip_set_string(void* i_image, const char* i_id, const char* i_data) -{ - int rc; - P9XipItem item; - char* dest; - - rc = p9_xip_find(i_image, i_id, &item); - - if (!rc) - { - switch (item.iv_type) - { - case P9_XIP_STRING: - dest = (char*)(item.iv_imageData); - - if (strlen(dest) < strlen(i_data)) - { - memcpy(dest, i_data, strlen(dest)); - } - else - { - strcpy(dest, i_data); - } - - break; - - default: - rc = TRACE_ERROR(P9_XIP_TYPE_ERROR); - break; - } - } - - return rc; -} - - -int -p9_xip_write_uint64(void* io_image, - const uint64_t i_imageAddress, - const uint64_t i_data) -{ - int rc; - - do - { - rc = xipQuickCheck(io_image, 0); - - if (rc) - { - break; - } - - rc = xipValidateImageAddress(io_image, i_imageAddress, 8); - - if (rc) - { - break; - } - - if (i_imageAddress % 8) - { - rc = TRACE_ERROR(P9_XIP_ALIGNMENT_ERROR); - break; - } - - *((uint64_t*)xipImage2Host(io_image, i_imageAddress)) = - htobe64(i_data); - - } - while(0); - - return rc; -} - - -int -p9_xip_delete_section(void* io_image, - void* o_imageBuf, - const uint32_t i_imageBufSize, - const int i_sectionId) -{ - int rc, final; - P9XipSection section; - size_t imageSize; - uint8_t bImageChanged = 0; // Tracks if io_image has been modified. - - do - { - - // Get image size. We'll need it a lot. - - imageSize = xipImageSize(io_image); - - // Parm check 1: imageBufSize - // - Must be >=imageSize for a valid imageBuf buffer - - if (i_imageBufSize < imageSize && o_imageBuf != NULL) - { - rc = TRACE_ERRORX(P9_XIP_WOULD_OVERFLOW, - "xip_delete_section(): imageBufSize too small"); - break; - } - - // Parm check 2: sectionId - // - It is illegal to remove the .header. It would kill the image. - - if (i_sectionId == P9_XIP_SECTION_HEADER) - { - rc = TRACE_ERRORX(P9_XIP_SECTION_ERROR, - "xip_delete_section(): It is illegal to remove .header"); - break; - } - - // Copy io_image to o_imageBuf if a valid imageBuf ptr is - // supplied, i.e., imageBuf!=NULL. We'll need a reference copy - // of any delected section to be re-appended after the section - // delete process is done. - if (o_imageBuf != NULL) - { - // We always return a copy of the original input image. - memcpy(o_imageBuf, io_image, imageSize); - } - - // Check the image - - rc = xipQuickCheck(io_image, 1); - - if (rc) - { - break; - } - - // Deleting an empty section is a NOP. Otherwise the section must be - // the final section of the image. Update the sizes and re-establish - // the final image alignment. - - rc = p9_xip_get_section(io_image, i_sectionId, §ion); - - if (rc) - { - break; - } - - if (section.iv_size == 0) - { - break; - } - - // Determine last image section. - - rc = xipFinalSection(io_image, &final); - - if (rc) - { - break; - } - - // Now, delete necessary sections in order of highest section offset - // to the offset of the section, i_sectionId, to be removed. - - if (final == i_sectionId) - { - rc = xipDeleteLastSection(io_image, i_sectionId); - - bImageChanged = 1; - - break; - } - else - { - // Check for imageBuf ptr violation. If this fails, this is - // catastrophic since we don't have a reference copy of the input - // image (i.e, the memcpy of the image earlier wasn't executed.) - - if (o_imageBuf == NULL) - { - rc = TRACE_ERRORX(P9_XIP_NULL_BUFFER, - "xip_delete_section(): Can't copy image into NULL buffer\n"); - break; - } - - // Delete sections, in order, that have offset addresses higher - // than i_sectionId and make a note of the order which is to - // be used when re-appending. Then delete i_sectionId. - - uint8_t sectionOrder[P9_XIP_SECTIONS]; - uint8_t orderIdx = 0; - - do - { - - rc = xipFinalSection(io_image, &final); - - if (rc) - { - break; - } - - // It is illegal to remove .header. It would kill the image. - if (final == P9_XIP_SECTION_HEADER) - { - rc = TRACE_ERRORX(P9_XIP_SECTION_ERROR, - "xip_delete_section(): Code bug: Attempt to remove .header"); - break; - } - - if (final != i_sectionId) - { - sectionOrder[orderIdx] = final; - orderIdx++; - } - - rc = xipDeleteLastSection(io_image, final); - - bImageChanged = 1; - - if (rc) - { - break; - } - - } - while (final != i_sectionId); - - if (rc) - { - break; - } - - // Reappend previously deleted sections in original order - - do - { - - orderIdx--; - rc = p9_xip_get_section(o_imageBuf, sectionOrder[orderIdx], §ion); - - if (rc) - { - break; - } - - rc = p9_xip_append( io_image, - sectionOrder[orderIdx], - (void*)(((uint8_t*)o_imageBuf) + section.iv_offset), - (const uint32_t)section.iv_size, - (const uint32_t)imageSize, - NULL ); - - if (rc) - { - break; - } - - } - while (orderIdx); - - break; - } - - } - while (0); - - // Restore broken input image in case of rc!=0. But only do so if input - // image has changed. - - if (rc && bImageChanged) - { - memcpy(io_image, o_imageBuf, imageSize); - } - - return rc; -} - - -#ifndef PPC_HYP - -// This API is not needed by PHYP procedures, and is elided since PHYP does -// not support malloc(). - -int -p9_xip_duplicate_section(const void* i_image, - const int i_sectionId, - void** o_duplicate, - uint32_t* o_size) -{ - P9XipSection section; - int rc; - - *o_duplicate = 0; - - do - { - rc = xipQuickCheck(i_image, 0); - - if (rc) - { - break; - } - - rc = p9_xip_get_section(i_image, i_sectionId, §ion); - - 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, §ion); - - 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, §ion) != 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, §ion); - - if (rc) - { - break; - } - - if (section.iv_size == 0) - { - rc = TRACE_ERROR(P9_XIP_SECTION_ERROR); - break; - } - - if (i_offset > (section.iv_offset + section.iv_size)) - { - rc = TRACE_ERROR(P9_XIP_INVALID_ARGUMENT); - break; - } - - *o_imageAddress = xipLinkAddress(i_image) + section.iv_offset + i_offset; - - if (*o_imageAddress % 4) - { - rc = TRACE_ERROR(P9_XIP_ALIGNMENT_ERROR); - break; - } - - } - while(0); - - return rc; -} - - -int -p9_xip_image2section(const void* i_image, - const uint64_t i_imageAddress, - int* i_section, - uint32_t* i_offset) -{ - int rc; - - do - { - rc = xipQuickCheck(i_image, 0); - - if (rc) - { - break; - } - - rc = xipImage2Section(i_image, i_imageAddress, i_section, i_offset); - - } - while(0); - - return rc; -} - - -int -p9_xip_image2host(const void* i_image, - const uint64_t i_imageAddress, - void** o_hostAddress) -{ - int rc; - - do - { - rc = xipQuickCheck(i_image, 0); - - if (rc) - { - break; - } - - if ((i_imageAddress < xipLinkAddress(i_image)) || - (i_imageAddress > - (xipLinkAddress(i_image) + xipImageSize(i_image)))) - { - rc = TRACE_ERROR(P9_XIP_INVALID_ARGUMENT); - break; - } - - *o_hostAddress = - xipHostAddressFromOffset(i_image, - i_imageAddress - xipLinkAddress(i_image)); - } - while(0); - - return rc; -} - - -int -p9_xip_host2image(const void* i_image, - void* i_hostAddress, - uint64_t* o_imageAddress) -{ - int rc; - - do - { - rc = xipQuickCheck(i_image, 0); - - if (rc) - { - break; - } - - if ((i_hostAddress < i_image) || - (i_hostAddress > - xipHostAddressFromOffset(i_image, xipImageSize(i_image)))) - { - rc = TRACE_ERROR(P9_XIP_INVALID_ARGUMENT); - break; - } - - *o_imageAddress = xipLinkAddress(i_image) + - ((unsigned long)i_hostAddress - (unsigned long)i_image); - - if (*o_imageAddress % 4) - { - rc = TRACE_ERROR(P9_XIP_ALIGNMENT_ERROR); - break; - } - } - while(0); - - return rc; -} - - -void -p9_xip_translate_header(P9XipHeader* o_dest, const P9XipHeader* i_src) -{ -#ifndef _BIG_ENDIAN - int i; - P9XipSection* destSection; - const P9XipSection* srcSection; - -#if P9_XIP_HEADER_VERSION != 9 -#error This code assumes the P9-XIP header version 9 layout -#endif - - o_dest->iv_magic = htobe64(i_src->iv_magic); - o_dest->iv_L1LoaderAddr = htobe64(i_src->iv_L1LoaderAddr); - o_dest->iv_L2LoaderAddr = htobe64(i_src->iv_L2LoaderAddr); - o_dest->iv_kernelAddr = htobe64(i_src->iv_kernelAddr); - o_dest->iv_linkAddress = htobe64(i_src->iv_linkAddress); - - memset(o_dest->iv_reserved64, 0, sizeof(i_src->iv_reserved64)); - - for (i = 0, destSection = o_dest->iv_section, - srcSection = i_src->iv_section; - i < P9_XIP_SECTIONS; - i++, destSection++, srcSection++) - { - xipTranslateSection(destSection, srcSection); - } - - o_dest->iv_imageSize = htobe32(i_src->iv_imageSize); - o_dest->iv_buildDate = htobe32(i_src->iv_buildDate); - o_dest->iv_buildTime = htobe32(i_src->iv_buildTime); - memcpy(o_dest->iv_buildTag, i_src->iv_buildTag, - sizeof(i_src->iv_buildTag)); - - o_dest->iv_headerVersion = i_src->iv_headerVersion; - o_dest->iv_normalized = i_src->iv_normalized; - o_dest->iv_tocSorted = i_src->iv_tocSorted; - - memset(o_dest->iv_reserved8, 0, sizeof(i_src->iv_reserved8)); - - memcpy(o_dest->iv_buildUser, i_src->iv_buildUser, - sizeof(i_src->iv_buildUser)); - memcpy(o_dest->iv_buildHost, i_src->iv_buildHost, - sizeof(i_src->iv_buildHost)); - memcpy(o_dest->iv_reservedChar, i_src->iv_reservedChar, - sizeof(i_src->iv_reservedChar)); -#else - - if (o_dest != i_src) - { - *o_dest = *i_src; - } - -#endif /* _BIG_ENDIAN */ -} - - -int -p9_xip_map_toc(void* io_image, - int (*i_fn)(void* io_image, - const P9XipItem* i_item, - void* io_arg), - void* io_arg) -{ - int rc; - P9XipToc* imageToc; - P9XipItem item; - size_t entries; - - do - { - rc = xipQuickCheck(io_image, 0); - - if (rc) - { - break; - } - - rc = p9_xip_get_toc(io_image, &imageToc, &entries, 0, 0); - - if (rc) - { - break; - } - - for (; entries--; imageToc++) - { - rc = xipDecodeToc(io_image, imageToc, &item); - - if (rc) - { - break; - } - - rc = i_fn(io_image, &item, io_arg); - - if (rc) - { - break; - } - } - } - while(0); - - return rc; -} diff --git a/src/import/chips/p9/xip/p9_xip_image.h b/src/import/chips/p9/xip/p9_xip_image.h index 3961478d..484ce5a8 100644 --- a/src/import/chips/p9/xip/p9_xip_image.h +++ b/src/import/chips/p9/xip/p9_xip_image.h @@ -238,6 +238,9 @@ typedef enum { /// gaurantee that the something will be able to complete any 8-byte load/store. #define P9_XIP_FINAL_ALIGNMENT 8 +/// Local undefined DD level value. +#define P9_XIP_UNDEFINED_DDLEVEL (uint8_t)0xff + //////////////////////////////////////////////////////////////////////////// // C Definitions @@ -306,8 +309,12 @@ typedef struct /// address. Alignment specifications are required to be a power-of-2. uint8_t iv_alignment; + /// Indicate if section has DD-level support. This value must be set + /// to either 1 for true or 0 for false (default). + uint8_t iv_ddSupport; + /// Reserved structure alignment padding; Pad to 12 bytes - uint8_t iv_reserved8[3]; + uint8_t iv_reserved8[2]; } P9XipSection; @@ -683,13 +690,21 @@ p9_xip_image_size(void* i_image, uint32_t* o_size); /// \param[out] o_hostSection Updated to contain the section table entry /// translated to host byte order. /// +/// \param[in] i_ddLevel Specified the DD level of the sub-section within +/// the XIP section to be extracted. +/// /// \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, +#ifdef __PPE__ P9XipSection* o_hostSection); +#else + P9XipSection* o_hostSection, + uint8_t i_ddLevel=P9_XIP_UNDEFINED_DDLEVEL); +#endif /// Endian translation of a P9XipHeader object @@ -1150,6 +1165,9 @@ p9_xip_duplicate_section(const void* i_image, /// byte of the appended data within the indicated section. This return value /// is invalid in the event of a non-0 return code. /// +/// \param[in] i_ddSupport Specifies if the section contains ddLevel sub- +/// sections (=1) or if it does not have ddLevel support (=0). +/// /// 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 @@ -1200,7 +1218,8 @@ p9_xip_append(void* io_image, const void* i_data, const uint32_t i_size, const uint32_t i_allocation, - uint32_t* o_sectionOffset); + uint32_t* o_sectionOffset, + uint8_t i_ddSupport); /// Convert a P9-XIP section offset to a relocatable IMAGE address @@ -1348,6 +1367,27 @@ p9_xip_get_toc(void* i_image, char** o_strings); +/// Inform caller if specified sectionId has DD support +/// +/// \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_bDdSupport Updated to contain true or false whether +/// sectionId has DD support or not. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref p9_xip_image_errors +#ifndef __PPE__ +int +p9_xip_dd_section_support(const void* i_image, + const int i_sectionId, + bool& o_bDdSupport); +#endif + + /// \brief Decode a TOC entry from dump file /// ///\param[in] - i_image - seeprom image @@ -1458,6 +1498,12 @@ p9_xip_decode_toc_dump(void* i_image, void* i_dump, /// .rings seciton for specific dd level is larger than the allowable size #define P9_XIP_SBE_DD_SIZE_ERR 19 +/// Specified section has no ddLevel support +#define P9_XIP_NO_DDLEVEL_SUPPORT 20 + +/// Specified ddLevel was not found in section +#define P9_XIP_DDLEVEL_NOT_FOUND 21 + /// Applications can expand this macro to declare an array of string forms of /// the error codes if desired. #define P9_XIP_ERROR_STRINGS(var) \ @@ -1482,6 +1528,8 @@ p9_xip_decode_toc_dump(void* i_image, void* i_dump, "P9_XIP_NULL_BUFFER", \ "P9_XIP_CANT_RESTORE_IMAGE", \ "P9_XIP_SBE_DD_SIZE_ERR", \ + "P9_XIP_NO_DDLEVEL_SUPPORT", \ + "P9_XIP_DDLEVEL_NOT_FOUND", \ } /// Applications can use this macro to safely index the array of error diff --git a/src/import/chips/p9/xip/p9_xip_tool.C b/src/import/chips/p9/xip/p9_xip_tool.C index ab109c87..e6fe0793 100644 --- a/src/import/chips/p9/xip/p9_xip_tool.C +++ b/src/import/chips/p9/xip/p9_xip_tool.C @@ -40,6 +40,7 @@ #include #include #include +#include #undef P9_XIP_TOOL_VERBOSE @@ -72,10 +73,10 @@ enum LISTING_MODE_ID // p9_xip_tool [- ...] setv [ ... ] // p9_xip_tool [- ...] report [] // p9_xip_tool [- ...] attrdump -// p9_xip_tool [- ...] append
-// p9_xip_tool [- ...] extract
+// p9_xip_tool [- ...] append
[ ] +// p9_xip_tool [- ...] extract
[ ] // p9_xip_tool [- ...] delete
[ ... ] -// p9_xip_tool [- ...] dissect [table,short,normal(default),long,raw] +// p9_xip_tool [- ...] dissect [ table,short,normal(default),long,raw ] // p9_xip_tool [- ...] disasm // // This simple application uses the P9-XIP image APIs to normalize, search @@ -127,9 +128,18 @@ enum LISTING_MODE_ID // Currently the section must either be the final (highest address) section of // the image, or must be empty, in which case the append command creates the // section as the final section of the image. The 'append' command writes the -// relocatable image address where the input file was loaded to stdout. +// relocatable image address where the input file was loaded to stdout. The +// last argument, ddSupport, indicates if the section being added has ddLevel +// metadata support (=1) or not (=0). If this arg is omitted it's assumed +// to be false (=0). // -// The 'extract' command extracts a sections from the binary image. +// The 'extract' command extracts a section from the binary image. The last +// argument, ddLevel, indicates [in hex] the DD level to be extracted. If +// the section doesn't have DD level support, a message is returned stating +// that and to reissue the command w/o the ddLevel arg. If the section does +// have DD support but the specified ddLevel cannot be found, a message is +// returned stating that and no section is returned. If the arg is omitted, +// the entire XIP section is returned // // The 'delete' command deletes 0 or more sections, starting with . // Each section to be deleted must either be the final (highest address) @@ -165,11 +175,11 @@ const char* g_usage = " p9_xip_tool [-i ...] setv [ ... ]\n" " p9_xip_tool [-i ...] report []\n" " p9_xip_tool [-i ...] attrdump \n" - " p9_xip_tool [-i ...] append
\n" - " p9_xip_tool [-i ...] extract
\n" + " p9_xip_tool [-i ...] append
[ ]\n" + " p9_xip_tool [-i ...] extract
[ ]\n" " p9_xip_tool [-i ...] delete
[ ... ]\n" " p9_xip_tool [-i ...] dis
\n" - " p9_xip_tool [-i ...] dissect [table,short,normal(default),long,raw]\n" + " p9_xip_tool [-i ...] dissect [ table,short,normal(default),long,raw ]\n" " p9_xip_tool [-i ...] disasm \n" " p9_xip_tool [-i ...] check-sbe-ring-section
\n" "\n" @@ -222,9 +232,18 @@ const char* g_usage = "Currently the section must either be the final (highest address) section of\n" "the image, or must be empty, in which case the append command creates the\n" "section as the final section of the image. The 'append' command writes the\n" - "relocatable image address where the input file was loaded to stdout.\n" + "relocatable image address where the input file was loaded to stdout. The\n" + "last argument, ddSupport, indicates if the section being added has ddLevel\n" + "metadata support (=1) or not (=0). If this arg is omitted, it's assumed\n" + "to be false (=0).\n" "\n" - "The 'extract' command extracs a sections from a binary image.\n" + "The 'extract' command extracts a section from the binary image. The last\n" + "argument, ddLevel, indicates [in hex] the DD level to be extracted. If\n" + "the section doesn't have DD level support, a message is returned stating\n" + "that and to reissue the command w/o the ddLevel arg. If the section does\n" + "have DD support but the specified ddLevel cannot be found, a message is\n" + "returned stating that and no section is returned. If the arg is omitted,\n" + "the entire XIP section is returned." "\n" "The 'delete' command deletes 0 or more sections, starting with .\n" "Each section to be deleted must either be the final (highest address)\n" @@ -322,12 +341,12 @@ static inline const char* get_sectionName(uint64_t magic, int index) // Determine index of section given by its name in section table -static inline int get_sectionId(uint64_t i_magic, const char* i_section) +static inline int get_sectionId(uint64_t i_magic, const char* i_sectionName) { int i; for (i = 0; i < P9_XIP_SECTIONS; i++) - if (strcmp(i_section, get_sectionName(i_magic, i)) == 0) + if (strcmp(i_sectionName, get_sectionName(i_magic, i)) == 0) { return i; } @@ -566,15 +585,16 @@ dumpHeader(void* i_image) printf("\n"); printf("Section Table :\n\n"); - printf(" Name Alignment Start End Size\n"); + printf(" Name Align DD Start End Size\n"); printf("\n"); for (i = 0; i < P9_XIP_SECTIONS; i++) { section = &(header.iv_section[i]); - printf(" %-16s %d 0x%08x ", + printf(" %-16s %d %d 0x%08x ", get_sectionName(header.iv_magic, i), section->iv_alignment, + section->iv_ddSupport, section->iv_offset); if (section->iv_size == 0) @@ -1090,6 +1110,7 @@ static int append(const char* i_imageFile, const int i_imageFd, void* io_image, int i_argc, const char** i_argv) { + uint8_t i_ddSupport = 0; int fileFd, newImageFd, sectionId, rc; struct stat buf; const char* section; @@ -1105,7 +1126,7 @@ append(const char* i_imageFile, const int i_imageFd, void* io_image, // Basic syntax check:
- if (i_argc != 2) + if (i_argc != 2 && i_argc != 3) { fprintf(stderr, g_usage); exit(1); @@ -1114,6 +1135,23 @@ append(const char* i_imageFile, const int i_imageFd, void* io_image, section = i_argv[0]; file = i_argv[1]; + if (i_argc == 3) + { + if (strcmp(i_argv[2], "1") == 0) + { + i_ddSupport = 1; + } + else if (strcmp(i_argv[2], "0") == 0) + { + i_ddSupport = 0; + } + else + { + fprintf(stderr, g_usage); + exit(1); + } + } + p9_xip_translate_header(&header, (P9XipHeader*)io_image); // Translate the section name to a section Id @@ -1190,9 +1228,13 @@ append(const char* i_imageFile, const int i_imageFd, void* io_image, // We will not fail for unaligned addresses, as we have no knowledge // of whether or why the user wants the final image address. - rc = p9_xip_append(newImage, sectionId, - appendImage, buf.st_size, - newSize, §ionOffset); + rc = p9_xip_append(newImage, + sectionId, + appendImage, + buf.st_size, + newSize, + §ionOffset, + i_ddSupport); if (rc) { @@ -1248,63 +1290,140 @@ append(const char* i_imageFile, const int i_imageFd, void* io_image, return rc; } -// Extract section from a file +// Extract section from an image incl a DD-specific sub-section within an XIP section. static int extract(const char* i_imageFile, const int i_imageFd, void* io_image, int i_argc, const char** i_argv) { - int fileFd, sectionId, rc; + int rc = 0; + const char* i_sectionName; //Direct copy of input arg, thus i_ + const char* i_fileName; //Same + std::string i_ddLevelStr; //Same + uint8_t ddLevel = P9_XIP_UNDEFINED_DDLEVEL; + bool bDdSuppExpected = false; + int fileFd, sectionId; void* newImage; - const char* section; - const char* file; P9XipHeader header; - P9XipSection* xSection; - uint32_t size; - uint32_t offset; + P9XipSection* xSection; // XIP section of i_section + P9XipSection xDdSection; // Extracted XIP (self) or Dd section of i_section do { - if (i_argc != 2) + if (i_argc != 2 && i_argc != 3) { fprintf(stderr, g_usage); exit(1); } - section = i_argv[0]; - file = i_argv[1]; - - printf("%s %s\n", section , file); + i_sectionName = i_argv[0]; + i_fileName = i_argv[1]; p9_xip_translate_header(&header, (P9XipHeader*)io_image); - - sectionId = get_sectionId(header.iv_magic, section); + sectionId = get_sectionId(header.iv_magic, i_sectionName); if (sectionId < 0) { - fprintf(stderr, "Unrecognized section name : '%s;\n", section); + fprintf(stderr, "\nUnrecognized section name : '%s;\n", i_sectionName); exit(1); } xSection = &(header.iv_section[sectionId]); - size = xSection->iv_size; - offset = xSection->iv_offset; + printf("\nInput parms to the \"extract\" command:\n"\ + " Section: %s\n"\ + " Output file: %s\n", + i_sectionName, i_fileName); - printf("%-16s 0x%08x 0x%08x (%d)\n", - section, offset, size, size); + ddLevel = P9_XIP_UNDEFINED_DDLEVEL; + bDdSuppExpected = false; - newImage = malloc(size); + if (i_argc == 3) + { + i_ddLevelStr = i_argv[2]; + + bDdSuppExpected = true; + + printf(" DD level (input): %s\n", + i_ddLevelStr.c_str()); + } + + if (bDdSuppExpected) + { + if (xSection->iv_ddSupport) + { + if (i_ddLevelStr.size() != 2 && i_ddLevelStr.size() != 4) + { + fprintf(stderr, "\nThe specified ddLevel \"%s\" has an unsupported format.\n", + i_ddLevelStr.c_str()); + fprintf(stderr, "Specify ddLevel in hex format, e.g. \"0x10\" or \"10\"\n\n"); + exit(1); + } + + ddLevel = strtol(i_ddLevelStr.c_str(), NULL, 16); + + printf(" DD level (hex converted): 0x%x\n", + ddLevel); + } + else + { + fprintf(stderr, "\nThe section \"%s\" has no DD level support.\n", i_sectionName); + fprintf(stderr, "To extract the entire section, omit the \"ddLevel\" arg.\n\n"); + exit(1); + } + } + + printf("\nThe specified XIP section has the following attributes:\n"\ + " Offset: 0x%08x\n"\ + " Size (size): 0x%08x (%d)\n"\ + " DD support: %d\n", + xSection->iv_offset, xSection->iv_size, xSection->iv_size, xSection->iv_ddSupport); + + if (ddLevel == 0) + { + ddLevel = P9_XIP_UNDEFINED_DDLEVEL; + // Even though this may seem like we should just exit here, we'll leave it up + // to xip_get_section what to do in this case. Who knows, maybe it'll eventually + // return a list of supported DD levels. + } + +#ifdef __PPE__ + rc = p9_xip_get_section( io_image, sectionId, &xDdSection); +#else + rc = p9_xip_get_section( io_image, sectionId, &xDdSection, ddLevel); +#endif + + switch (rc) + { + case 0: + break; + + case P9_XIP_NO_DDLEVEL_SUPPORT: + fprintf(stderr, "\nThere is no support for DD level extraction yet.\n"); + fprintf(stderr, "To extract the entire section, omit the \"ddLevel\" arg.\n\n"); + exit(1); + + case P9_XIP_DDLEVEL_NOT_FOUND: + fprintf(stderr, "\nA sub-section w/the specified ddLevel (=0x%x) was not found.\n", ddLevel); + fprintf(stderr, "To extract the entire section, omit the \"ddLevel\" arg.\n\n"); + exit(1); + + default: + fprintf(stderr, "\np9_xip_get_section() failed w/rc = %d\n\n", rc); + exit(1); + } + + newImage = malloc(xSection->iv_size); if (newImage == 0) { - fprintf(stderr, "Can't malloc() a buffer for the new image\n"); + fprintf(stderr, "\nCan't malloc() a buffer for the new image\n"); exit(1); } - memcpy(newImage, (void*)((uint64_t)io_image + offset), size); + memcpy( newImage, (void*)((uint64_t)io_image + xDdSection.iv_offset), xDdSection.iv_size); - fileFd = open(file, O_CREAT | O_WRONLY | O_TRUNC, 0755); + fileFd = open(i_fileName, O_CREAT | O_WRONLY | O_TRUNC, 0755); if (fileFd < 0) { @@ -1312,9 +1431,9 @@ extract(const char* i_imageFile, const int i_imageFd, void* io_image, exit(1); } - rc = write(fileFd, newImage, size); + rc = write(fileFd, newImage, xDdSection.iv_size); - if ((rc < 0) || ((uint32_t)rc != size)) + if ((rc < 0) || ((uint32_t)rc != xDdSection.iv_size)) { perror("write() of fixed section : "); exit(1); diff --git a/src/import/tools/imageProcs/p9_ipl_build.C b/src/import/tools/imageProcs/p9_ipl_build.C index a6b13d40..4f4687e9 100644 --- a/src/import/tools/imageProcs/p9_ipl_build.C +++ b/src/import/tools/imageProcs/p9_ipl_build.C @@ -217,7 +217,8 @@ int append_ring_block_to_image( char* io_sbeImage, i_ringBlock, i_blockSize, io_sbeImageSize, - &unused_parm ); + &unused_parm, + 0 ); if(rc) { -- cgit v1.2.1