diff options
author | Mark Wenning <wenning@us.ibm.com> | 2012-05-29 12:02:40 -0500 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2012-06-11 11:45:48 -0500 |
commit | 882332b0941f2913111c033c4f90bd6e4ae05da0 (patch) | |
tree | 5c85e1bd8590e26de21c946bb918c0ec18f2be4f | |
parent | 43705c216502430ed9beb464a991c8e63a60bedb (diff) | |
download | talos-hostboot-882332b0941f2913111c033c4f90bd6e4ae05da0.tar.gz talos-hostboot-882332b0941f2913111c033c4f90bd6e4ae05da0.zip |
proc_slw_build HWP support
Change-Id: Ib704518ebe1b32a125f93be468f05d0d4c1572bb
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/1125
Tested-by: Jenkins Server
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
25 files changed, 11034 insertions, 50 deletions
diff --git a/src/include/stdint.h b/src/include/stdint.h index e545e0f29..d794b7867 100644 --- a/src/include/stdint.h +++ b/src/include/stdint.h @@ -1,48 +1,53 @@ -// IBM_PROLOG_BEGIN_TAG -// This is an automatically generated prolog. -// -// $Source: src/include/stdint.h $ -// -// IBM CONFIDENTIAL -// -// COPYRIGHT International Business Machines Corp. 2010 - 2011 -// -// p1 -// -// Object Code Only (OCO) source materials -// Licensed Internal Code Source Materials -// IBM HostBoot Licensed Internal Code -// -// The source code for this program is not published or other- -// wise divested of its trade secrets, irrespective of what has -// been deposited with the U.S. Copyright Office. -// -// Origin: 30 -// -// IBM_PROLOG_END +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/include/stdint.h $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2010-2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ #ifndef __STDINT_H #define __STDINT_H #include <stddef.h> -typedef signed char int8_t; -typedef short int int16_t; -typedef int int32_t; -typedef long int int64_t; +typedef signed char int8_t; +typedef short int int16_t; +typedef int int32_t; +typedef long int int64_t; typedef unsigned char uint8_t; typedef unsigned short int uint16_t; typedef unsigned int uint32_t; typedef unsigned long int uint64_t; -typedef uint64_t size_t; -typedef int64_t ssize_t; +typedef uint64_t size_t; +typedef int64_t ssize_t; -typedef ssize_t ptrdiff_t; +typedef ssize_t ptrdiff_t; #define UINT8_MAX (255U) #define UINT16_MAX (65535U) #define UINT32_MAX (4294967295U) #define UINT64_MAX (18446744073709551615U) +// add (u)intptr_t support +typedef long int intptr_t; +typedef unsigned long int uintptr_t; + #endif diff --git a/src/include/usr/vmmconst.h b/src/include/usr/vmmconst.h index 516a45137..a43a70a7a 100644 --- a/src/include/usr/vmmconst.h +++ b/src/include/usr/vmmconst.h @@ -5,7 +5,7 @@ * * IBM CONFIDENTIAL * - * COPYRIGHT International Business Machines Corp. 2011 - 2012 + * COPYRIGHT International Business Machines Corp. 2011-2012 * * p1 * @@ -83,7 +83,9 @@ enum BlockPriority #define SLBE_b 12 /** Hardwired pointer to output PORE image, temporary location */ -#define OUTPUT_PORE_IMAGE 0x780000 +/** MAX image size is 512 K */ +#define OUTPUT_PORE_IMG_ADDR 0x780000 +#define MAX_OUTPUT_PORE_IMG_SIZE 512*1024 /** diff --git a/src/usr/hwpf/hwp/build_winkle_images/build_winkle_images.C b/src/usr/hwpf/hwp/build_winkle_images/build_winkle_images.C index fa39e9b26..e2ad1fec6 100644 --- a/src/usr/hwpf/hwp/build_winkle_images/build_winkle_images.C +++ b/src/usr/hwpf/hwp/build_winkle_images/build_winkle_images.C @@ -58,7 +58,7 @@ #include "build_winkle_images.H" // Uncomment these files as they become available: -// #include "host_build_winkle/host_build_winkle.H" +#include "proc_slw_build/proc_slw_build.H" // #include "proc_set_pore_bar/proc_set_pore_bar.H" namespace BUILD_WINKLE_IMAGES @@ -77,7 +77,7 @@ using namespace DeviceFW; * */ void * const g_pOutputPoreImg - = reinterpret_cast<void * const >(OUTPUT_PORE_IMAGE); + = reinterpret_cast<void * const >(OUTPUT_PORE_IMG_ADDR); /** * @brief Load PORE image and return a pointer to it, or NULL @@ -164,7 +164,7 @@ void call_host_build_winkle( void *io_pArgs ) const char *l_pPoreImage = NULL; size_t l_poreSize = 0; void *l_pImageOut = NULL; - uint32_t l_sizeImageOut = 0; + uint32_t l_sizeImageOut = MAX_OUTPUT_PORE_IMG_SIZE; TRACDCOMP( ISTEPS_TRACE::g_trac_isteps_trace, @@ -213,23 +213,22 @@ void call_host_build_winkle( void *io_pArgs ) (const_cast<TARGETING::Target*>(l_cpu_target)) ); // - // stub - get address of output buffer for PORE image + // stub - get address of output buffer for PORE image for this CPU, + // and load it there // - l_pImageOut = g_pOutputPoreImg; + l_pImageOut = g_pOutputPoreImg; + l_sizeImageOut = MAX_OUTPUT_PORE_IMG_SIZE; + -#if 0 - // $$$$$ comment out for now $$$$$ // call the HWP with each fapi::Target FAPI_INVOKE_HWP( l_errl, proc_slw_build, l_fapi_cpu_target, - reinterpret_cast<const void*>(poreImage), - reinterpret_cast<uint32_t>(poreSize), + reinterpret_cast<const void*>(l_pPoreImage), + static_cast<uint32_t>(l_poreSize), l_pImageOut, &l_sizeImageOut ); -#endif - if ( l_errl ) { TRACFCOMP(ISTEPS_TRACE::g_trac_isteps_trace, diff --git a/src/usr/hwpf/hwp/build_winkle_images/makefile b/src/usr/hwpf/hwp/build_winkle_images/makefile index f03ef1d30..c970dfd84 100644 --- a/src/usr/hwpf/hwp/build_winkle_images/makefile +++ b/src/usr/hwpf/hwp/build_winkle_images/makefile @@ -1,4 +1,4 @@ -# IBM_PROLOG_BEGIN_TAG +# IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # $Source: src/usr/hwpf/hwp/build_winkle_images/makefile $ @@ -19,8 +19,7 @@ # # Origin: 30 # -# IBM_PROLOG_END - +# IBM_PROLOG_END_TAG ROOTPATH = ../../../../.. MODULE = build_winkle_images @@ -41,14 +40,24 @@ EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/build_winkle_images ## NOTE: add a new EXTRAINCDIR when you add a new HWP ## EXAMPLE: ## EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/build_winkle_images/<HWP_dir> +EXTRAINCDIR += ${ROOTPATH}/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build + +CUSTOMFLAGS+= -D __FAPI ## NOTE: add new object files when you add a new HWP -OBJS = build_winkle_images.o +OBJS = build_winkle_images.o \ + p8_image_help.o \ + p8_pore_static_data.o \ + p8_scan_compression.o \ + pore_inline_assembler.o \ + proc_slw_build.o \ + sbe_xip_image.o ## NOTE: add a new directory onto the vpaths when you add a new HWP ## EXAMPLE: # VPATH += ${ROOTPATH}/src/usr/hwpf/hwp/build_winkle_images/<HWP_dir> +VPATH += ${ROOTPATH}/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build ## Point to the PORE image in PNOR BINARY_FILES = $(IMGDIR)/procpore.dat:1f6e49c91e2a2b0df5fad6c215c8f09d9f19fce6 diff --git a/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/fapi_sbe_common.H b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/fapi_sbe_common.H new file mode 100644 index 000000000..24868bb52 --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/fapi_sbe_common.H @@ -0,0 +1,70 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/fapi_sbe_common.H $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +#ifndef __FAPI_SBE_COMMON_H +#define __FAPI_SBE_COMMON_H + +// $Id: fapi_sbe_common.H,v 1.1 2012/04/16 23:55:37 bcbrock Exp $ +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/fapi_sbe_common.H,v $ +//------------------------------------------------------------------------------ +// *! (C) Copyright International Business Machines Corp. 2011 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//------------------------------------------------------------------------------ +// *! OWNER NAME : Email: + +/// \file fapi_sbe_common.H +/// \brief Definitions common to FAPI and SBE procedures +/// +/// Several preprocessor macros are required to have different definitions in +/// C, C++ and SBE assembly procedures. These common forms are collected here. + +#if defined __ASSEMBLER__ + +#define CONST_UINT8_T(name, expr) .set name, (expr) +#define CONST_UINT32_T(name, expr) .set name, (expr) +#define CONST_UINT64_T(name, expr) .set name, (expr) + +#define ULL(x) x + +#elif defined __cplusplus + +#include <stdint.h> + +#define CONST_UINT8_T(name, expr) const uint8_t name = (expr); +#define CONST_UINT32_T(name, expr) const uint32_t name = (expr); +#define CONST_UINT64_T(name, expr) const uint64_t name = (expr); + +#define ULL(x) x##ull + +#else // C code + +// CONST_UINT[8,3,64]_T() can't be used in C code/headers; Use +// +// #define <symbol> <value> [ or ULL(<value>) for 64-bit constants + +#define ULL(x) x##ull + +#endif // __ASSEMBLER__ + +#endif // __FAPI_SBE_COMMON_H diff --git a/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_delta_scan_rw.h b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_delta_scan_rw.h new file mode 100644 index 000000000..6cdf89108 --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_delta_scan_rw.h @@ -0,0 +1,261 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_delta_scan_rw.h $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +//***** IMPORTANT - Assumptions (you may have to change these settings) ****** +#define ASM_RS4_LAUNCH_BUF_SIZE 24 // Byte size of binary RS4 launch buffer w/last two + // nops removed. +#define OVERRIDE_OFFSET 8 // Byte offset of forward pointer's addr relative + // to base forward pointer's addr. +#define SLW_MS_MAX_BUF_SIZE 50000000 // Max 50MB for SLW mainstore image. + +/***** Scan Control Regs *****/ +#define P8_PORE_CLOCK_CONTROLLER_REG 0x00030007 // Addr of clock ctrl scom reg +#define P8_PORE_SHIFT_REG 0x00038000 // Addr of scom reg that does scan ring shifting +#define P8_SCAN_CHECK_WORD 0xA5A55A5A // Header check word + +/***** Ring state *****/ +#define MAX_RING_SIZE 1000000 // This is the max binary ring size in bits + +// Debug and development stuff +#define IGNORE_FOR_NOW // Causes code sections to be ignored. +#define DEBUG_SUPPORT // Activates sbe-xip debug support. +#define PRINT_WF_DIS // Causes wf inline code to be disassembled and written to file. + +/***** Return codes *****/ +#define DSLWB_RING_SEARCH_MATCH 0 +#define DSLWB_RING_SEARCH_EXHAUST_MATCH 30 +#define DSLWB_RING_SEARCH_NO_MATCH 31 +#define DSLWB_RING_SEARCH_MESS 32 +#define DSLWB_SLWB_SUCCESS 0 +#define DSLWB_SLWB_NO_RING_MATCH 40 +#define DSLWB_SLWB_DX_ERROR 41 +#define DSLWB_SLWB_WF_ERROR 42 +#define DSLWB_SLWB_WF_IMAGE_ERROR 43 +#define DSLWB_SLWB_IMAGE_ERROR 44 +#define DSLWB_SLWB_UNKNOWN_ERROR 45 +#define IMGBUILD_SUCCESS 0 // Successful image build. +#define IMGBUILD_ERR_MEMORY 20 // Memory allocation error. +#define IMGBUILD_ERR_XIP_MISC 25 // Miscellaneous XIP image error. +#define IMGBUILD_ERR_SECTION_DELETE 50 // Err assoc w/deleting ELF section. +#define IMGBUILD_ERR_APPEND 51 // Err assoc w/appending to ELF section. +#define IMGBUILD_ERR_INCOMPLETE_IMG_BUILD 52 // The image was built, but with errors. +#define IMGBUILD_ERR_FWD_BACK_PTR_MESS 53 // Forward or backward pointer mess. +#define IMGBUILD_ERR_KEYWORD_NOT_FOUND 54 // Image keyword not found. +#define IMGBUILD_ERR_MISALIGNED_RING_LAYOUT 55 // Ring layout is misaligned. +#define IMGBUILD_ERR_IMAGE_TOO_LARGE 56 // Image too large. Exceeded max size. +#define IMGBUILD_ERR_CHECK_CODE 60 // Coding problem - impossible state. + +#ifdef __FAPI +#define MY_INF(_fmt_, _args_...) FAPI_INF(_fmt_, ##_args_) +#ifndef SLW_COMMAND_LINE +#define MY_ERR(_fmt_, _args_...) FAPI_ERR(_fmt_, ##_args_) +#else +#define MY_ERR(_fmt_, _args_...) FAPI_INF(_fmt_, ##_args_) +#endif // End of SLW_COMMAND_LINE +#define MY_DBG(_fmt_, _args_...) FAPI_DBG(_fmt_, ##_args_) +#else +#define MY_INF(_fmt_, _args_...) fprintf(stdout, _fmt_, ##_args_) +#define MY_ERR(_fmt_, _args_...) fprintf(stderr, _fmt_, ##_args_) +#define MY_DBG(_fmt_, _args_...) fprintf(stdout, _fmt_, ##_args_) +#endif // End of FAPI + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#ifdef SLW_COMMAND_LINE +#include <sys/mman.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#endif //End of SLW_COMMAND_LINE +#ifndef SLW_BUILD_WF_P0_FIX +#include "pore_bitmanip.H" +#endif // SLW_BUILD_WF_P0_FIX +#include "p8_pore_api.h" +#include "p8_pore_static_data.h" +#include "p8_scan_compression.H" +#include "sbe_xip_image.h" +#undef __PORE_INLINE_ASSEMBLER_C__ +#include "pore_inline.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Info: +// DeltaRingLayout describes the sequential order of the content in the compressed delta +// ring blocks in the .initf section in the SBE-XIP images. +// When creating the .initf delta ring blocks, the following rules must be followed: +// - Everything must be stored in BE format. +// - {entryOffset; sizeOfThis; sizeOfMeta; metaData} must be word-aligned to ensure +// that the {rs4Launch} starts on a word boundary. +// - {rs4Launch} must start on a word boundary (see earlier rule how to do that). +// - {entryOffset; sizeOfThis; sizeOfMeta; metaData; rs4Launch} must be double-word- +// aligned to ensure that {rs4Delta} starts on a double-word boundary. +// - {rs4Delta} must start on a double-word bournday (see earlier rule how to do that). +// +typedef struct { + uint64_t entryOffset; + uint64_t backItemPtr; + uint32_t sizeOfThis; + uint32_t sizeOfMeta; // Exact size of meta data. Arbitrary size. Not null terminated. + uint32_t ddLevel; + uint8_t sysPhase; + uint8_t override; + uint8_t reserved1; + uint8_t reserved2; + char *metaData; // Arbitrary size. Extra bytes to next alignment are random or 0s. + uint32_t *rs4Launch; // Code. Must be 4-byte aligned. + uint32_t *rs4Delta; // Data. Must be 8-byte aligned. + uint32_t *wfInline; // Code. Must be 4-byte aligned. +} DeltaRingLayout; + +typedef struct { + uint32_t sizeOfData; + char data[]; +} MetaData; + +int p8_ipl_build( void *i_imageIn, + uint32_t i_ddLevel, + void *i_imageOut, + uint32_t i_sizeImageOutMax); + +int get_ring_layout_from_image2( const void *i_imageIn, + uint32_t i_ddLevel, + uint8_t i_sysPhase, + DeltaRingLayout **o_rs4RingLayout, + void **nextRing); + +int write_ring_block_to_image( void *io_image, + DeltaRingLayout *i_ringBlock, + uint32_t i_sizeImageMax); + +int gen_ring_delta_state( + uint32_t bitLen, + uint32_t *i_init, + uint32_t *i_alter, + uint32_t *o_delta, + uint32_t verbose); + +int write_delta_ring_to_image( + char *i_fnImage, + CompressedScanData *i_RS4, + uint32_t i_ddLevel, + uint8_t i_sysPhase, + uint8_t i_override, + char *i_varName, + char *i_fnMetaData, + uint32_t verbose); + +int get_delta_ring_from_image( + char *i_fnImage, + char *i_varName, + uint32_t i_ddLevel, + uint8_t i_sysPhase, + uint8_t i_override, + MetaData **o_metaData, + CompressedScanData **o_deltaRingRS4, + uint32_t verbose); + +int write_wiggle_flip_to_image( + void *io_imageOut, + uint32_t *i_sizeImageMaxNew, + DeltaRingLayout *i_ringLayout, + uint32_t *i_wfInline, + uint32_t i_wfInlineLenInWords); + +int get_ring_layout_from_image( + const void *i_imageIn, + uint32_t i_ddLevel, + uint8_t i_sysPhase, + DeltaRingLayout *o_rs4RingLayout, + void **nextRing); + +int create_wiggle_flip_prg( + uint32_t *i_deltaRing, + uint32_t i_ringBitLen, + uint32_t i_scanSelectData, + uint32_t i_chipletID, + uint32_t **o_wfInline, + uint32_t *o_wfInlineLenInWords); + +int append_empty_section( + void *io_image, + uint32_t *i_sizeImageMaxNew, + uint32_t i_sectionId, + uint32_t i_sizeSection); + +void cleanup( + void *buf1=NULL, + void *buf2=NULL, + void *buf3=NULL, + void *buf4=NULL, + void *buf5=NULL); + +// Byte-reverse a 32-bit integer if on an LE machine +inline uint32_t myRev32(const uint32_t i_x) +{ + uint32_t rx; + +#ifdef _BIG_ENDIAN + rx = i_x; +#else + uint8_t *pix = (uint8_t*)(&i_x); + uint8_t *prx = (uint8_t*)(&rx); + + prx[0] = pix[3]; + prx[1] = pix[2]; + prx[2] = pix[1]; + prx[3] = pix[0]; +#endif + + return rx; +} + +// Byte-reverse a 64-bit integer if on a little-endian machine +inline uint64_t myRev64(const uint64_t i_x) +{ + uint64_t rx; + +#ifdef _BIG_ENDIAN + rx = i_x; +#else + uint8_t *pix = (uint8_t*)(&i_x); + uint8_t *prx = (uint8_t*)(&rx); + + prx[0] = pix[7]; + prx[1] = pix[6]; + prx[2] = pix[5]; + prx[3] = pix[4]; + prx[4] = pix[3]; + prx[5] = pix[2]; + prx[6] = pix[1]; + prx[7] = pix[0]; +#endif + + return rx; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_image_help.C b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_image_help.C new file mode 100644 index 000000000..6f0fe7af2 --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_image_help.C @@ -0,0 +1,718 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_image_help.C $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +/*------------------------------------------------------------------------------*/ +/* *! TITLE : p8_image_help.C */ +/* *! DESCRIPTION : Helper functions for building and extracting information */ +// from SBE-XIP images. +/* *! OWNER NAME : Michael Olsen cmolsen@us.ibm.com */ +// +/* *! EXTENDED DESCRIPTION : */ +// +/* *! USAGE : */ +// +/* *! ASSUMPTIONS : */ +// +/* *! COMMENTS : */ +// +/*------------------------------------------------------------------------------*/ + +#include "p8_delta_scan_rw.h" + +#ifdef __FAPI +#include <fapi.H> +#endif +extern "C" { + + +// get_ring_layout_from_image() +// +int get_ring_layout_from_image( const void *i_imageIn, + uint32_t i_ddLevel, + uint8_t i_sysPhase, + DeltaRingLayout *o_rs4RingLayout, + void **nextRing) +{ + uint32_t rc=0, rcLoc=0; + uint8_t bRingFound=0, bRingEOS=0; + DeltaRingLayout *thisRingLayout, *nextRingLayout; //Pointers into memory mapped image. DO NOT CHANGE MEMBERS! + uint32_t sizeInitf; + SbeXipSection hostSection; + void *initfHostAddress0; + + SBE_XIP_ERROR_STRINGS(errorStrings); + + // Always first get the .initf stats from the TOC: + // - .initf host address offset and + // - .initf size + // + rc = sbe_xip_get_section( i_imageIn, SBE_XIP_SECTION_RINGS, &hostSection); + if (rc) { + MY_ERR("ERROR : sbe_xip_get_section() failed: %s", SBE_XIP_ERROR_STRING(errorStrings, rc)); + MY_ERR("Probable cause:"); + MY_ERR("\tThe section (=SBE_XIP_SECTION_RINGS=%i) was not found.",SBE_XIP_SECTION_RINGS); + return IMGBUILD_ERR_KEYWORD_NOT_FOUND; + } + if (hostSection.iv_offset==0) { + MY_INF("INFO : No ring data exists for the section ID = SBE_XIP_SECTION_RINGS (ID=%i).",SBE_XIP_SECTION_RINGS); + return DSLWB_RING_SEARCH_NO_MATCH; // Implies exhaust search as well. + } + initfHostAddress0 = (void*)((uintptr_t)i_imageIn + hostSection.iv_offset); + sizeInitf = hostSection.iv_size; + + // On first call, get the base offset to the .initf section. + // On subsequent calls, we're into the search for ddLevel and sysPhase, so use nextRing instead. + // + if (*nextRing==NULL) + nextRingLayout = (DeltaRingLayout*)initfHostAddress0; + else + nextRingLayout = (DeltaRingLayout*)*nextRing; + + MY_DBG("initfHostAddress0 = 0x%016llx",(uint64_t)initfHostAddress0); + MY_DBG("sizeInitf = %i", sizeInitf); + MY_DBG("nextRingLayout = 0x%016llx",(uint64_t)nextRingLayout); + + // Populate the output RS4 ring BE layout structure as well as local structure in host LE format where needed. + // Note! Entire memory content is in BE format. So we do LE conversions where needed. + // + bRingFound = 0; + bRingEOS = 0; + + // SEARCH loop: Parse ring blocks successively until we find a ring that matches: + // ddLevel == i_ddLevel + // sysPhase == i_sysPhase + // + while (!bRingFound && !bRingEOS) { + thisRingLayout = nextRingLayout; + MY_DBG("Next backItemPtr = 0x%016llx",myRev64(thisRingLayout->backItemPtr)); + MY_DBG("Next ddLevel = 0x%02x",myRev32(thisRingLayout->ddLevel)); + MY_DBG("Next sysPhase = %i",thisRingLayout->sysPhase); + MY_DBG("Next override = %i",thisRingLayout->override); + MY_DBG("Next reserved1 = %i",thisRingLayout->reserved1); + MY_DBG("Next reserved2 = %i",thisRingLayout->reserved2); + + if (myRev32(thisRingLayout->ddLevel)==i_ddLevel) { // Is there a non-specific DD level, like for sys phase? + if ((thisRingLayout->sysPhase==0 && i_sysPhase==0) || + (thisRingLayout->sysPhase==1 && i_sysPhase==1) || + (thisRingLayout->sysPhase==2 && (i_sysPhase==0 || i_sysPhase==1))) { + bRingFound = 1; + MY_DBG("\tRing match found!"); + } + } + nextRingLayout = (DeltaRingLayout*)((uintptr_t)thisRingLayout + myRev32(thisRingLayout->sizeOfThis)); + *nextRing = (void*)nextRingLayout; + if (nextRingLayout>=(DeltaRingLayout*)((uintptr_t)initfHostAddress0+sizeInitf)) { + bRingEOS = 1; + *nextRing = NULL; + MY_DBG("\tRing search exhausted!"); + } + + } // End of SEARCH. + + if (bRingFound) { + if (bRingEOS) + rcLoc = DSLWB_RING_SEARCH_EXHAUST_MATCH; + else + rcLoc = DSLWB_RING_SEARCH_MATCH; + } + else { + *nextRing = NULL; + if (bRingEOS) + return DSLWB_RING_SEARCH_NO_MATCH; // Implies exhaust search as well. + else { + MY_ERR("Messed up ring search. Check code and .rings content. Returning nothing."); + return DSLWB_RING_SEARCH_MESS; + } + } + + o_rs4RingLayout->entryOffset = thisRingLayout->entryOffset; + o_rs4RingLayout->backItemPtr = thisRingLayout->backItemPtr; + o_rs4RingLayout->sizeOfThis = thisRingLayout->sizeOfThis; + o_rs4RingLayout->sizeOfMeta = thisRingLayout->sizeOfMeta; + o_rs4RingLayout->ddLevel = thisRingLayout->ddLevel; + o_rs4RingLayout->sysPhase = thisRingLayout->sysPhase; + o_rs4RingLayout->override = thisRingLayout->override; + o_rs4RingLayout->reserved1 = thisRingLayout->reserved1; + o_rs4RingLayout->reserved2 = thisRingLayout->reserved2; + o_rs4RingLayout->metaData = (char*)(&thisRingLayout->reserved2 + + sizeof(thisRingLayout->reserved2)); + o_rs4RingLayout->rs4Launch = (uint32_t*)((uintptr_t)thisRingLayout + + myRev64(thisRingLayout->entryOffset)); + // Since RS4 launch size is only word-aligned, make sure to point to nearest [higher] double-word boundary. + o_rs4RingLayout->rs4Delta = (uint32_t*)((((uintptr_t)thisRingLayout + + myRev64(thisRingLayout->entryOffset) + + ASM_RS4_LAUNCH_BUF_SIZE-1)/8+1)*8); + + // Check that the ring layout structure in the memory is double-word aligned. This must be so because: + // - The entryOffset address must be on an 8-byte boundary because the start of the .initf ELF section must + // be 8-byte aligned AND because the rs4Delta member is the last member and which must itself be 8-byte aligned. + // - These two things together means that both the beginning and end of the delta ring layout must be 8-byte + // aligned, and thus the whole block,i.e. sizeOfThis, must be 8-byte aligned. + // Also check that the RS4 delta ring is double-word aligned. + // Also check that the RS4 launcher is word aligned. + // + if (((uintptr_t)thisRingLayout-(uintptr_t)i_imageIn)%8 || + myRev32(o_rs4RingLayout->sizeOfThis)%8 || + (uintptr_t)o_rs4RingLayout->rs4Launch%4 || + (uintptr_t)o_rs4RingLayout->rs4Delta%8) { + MY_ERR("ERROR : Ring layout is not double-word-aligned or RS4 launcher is not word aligned."); + MY_ERR(" thisRingLayout#8 = 0x%016llx",(uint64_t)thisRingLayout%8); + MY_ERR(" myRev32(o_rs4RingLayout->sizeOfThis)#8 = %i",myRev32(o_rs4RingLayout->sizeOfThis)%8); + MY_ERR(" o_rs4RingLayout->rs4Launch#4 = 0x%016llx",(uint64_t)o_rs4RingLayout->rs4Launch%4); + MY_ERR(" o_rs4RingLayout->rs4Delta#8 = 0x%016llx",(uint64_t)o_rs4RingLayout->rs4Delta%8); + return IMGBUILD_ERR_MISALIGNED_RING_LAYOUT; + } + + if (*nextRing > (void*)((uintptr_t)initfHostAddress0 + sizeInitf)) { + MY_INF("INFO : Book keeping got messed up during .initf search. Initf section does not appear aligned."); + MY_INF("initfHostAddress0+sizeInitf = 0x%016llx",(uint64_t)initfHostAddress0+sizeInitf); + MY_INF("nextRing = %i",*(uint32_t*)nextRing); + MY_INF("Continuing..."); + } + + return rcLoc; +} + + + +// create_wiggle_flip_prg() function +// Notes: +// - WF procedure needs to be updated with polling protocol. +// - WF procedure needs to reflect P0/P1 usage policy +int create_wiggle_flip_prg( uint32_t *i_deltaRing, // scan ring delta state + uint32_t i_ringBitLen, // length of ring + uint32_t i_scanSelectData, // Scan ring modifier data + uint32_t i_chipletID, // Chiplet ID + uint32_t **o_wfInline, // location of the PORE instructions data stream + uint32_t *o_wfInlineLenInWords) // final length of data stream +{ + uint32_t rc=P8_PORE_SUCCESS_RC; //defined in p8_pore_api_const.h + uint32_t i=0; + uint32_t scanSelectAddr=0; + uint32_t scanRing_baseAddr=0; + uint32_t scanRing_poreAddr=0; + uint32_t scanRingCheckWord=0; + uint32_t count=0; + uint32_t rotateLen=0, remainder=0, remainingBits=0; + uint32_t osIndex=0; + int pgas_rc=0; + uint64_t pore_imm64b=0; + uint32_t maxWfInlineLenInWords = 10*MAX_RING_SIZE/32; + PoreInlineContext ctx; + PoreInlineLocation src3=0, tgt3=0; + + *o_wfInline = (uint32_t*)malloc(maxWfInlineLenInWords); + + //pore_inline_context_create(&ctx, buf, P8_PORE_BUFSIZE * 4, 0, PORE_INLINE_CHECK_PARITY); + pore_inline_context_create(&ctx, *o_wfInline, maxWfInlineLenInWords * 4, 0, 0); + + // Get chiplet and Ring Addr info. + // -------------------------------------------------------------------------- + + // Set Default scanselq addr and scanring addr vars + scanSelectAddr=P8_PORE_CLOCK_CONTROLLER_REG; // 0x00030007: port 3 - clock cotrol endpt, x07- scanselq (regin & types) + // Descr: Addr of clock control SCOM reg. + scanRing_baseAddr=P8_PORE_SHIFT_REG; // 0x00038000: port 3, addr bit 16 must be set to 1 + // Also called GENERIC_CLK_SCANDATA0 + // Descr: SCOM reg for scan ring shifting. + scanRing_poreAddr=scanRing_baseAddr; // Init scan ring rotate addr + scanRingCheckWord=P8_SCAN_CHECK_WORD; // Header check word for checking ring write was successful + + // Program scanselq reg for scan clock control setup before ring scan + // -------------------------------------------------------------------------- + +#ifndef SLW_BUILD_WF_P0_FIX +// The following fix is a direct copy of the setp1_mcreadand macro in ./ipl/sbe/p8_slw.H + uint64_t CLEAR_MC_TYPE_MASK=0x47; + PoreInlineLocation src1=0, src2=0, tgt1=0, tgt2=0; + pgas_rc = pore_MR( &ctx, D1, P0) || + pore_ANDI( &ctx, D1, D1, BIT(57)) || + PORE_LOCATION( &ctx, src1) || + pore_BRANZ( &ctx, D1, src1) || + pore_MR( &ctx, P1, P0) || + PORE_LOCATION( &ctx, src2) || + pore_BRA( &ctx, tgt2) || + PORE_LOCATION( &ctx, tgt1) || + pore_MR( &ctx, D1, P0) || + pore_ANDI( &ctx, D1, D1, CLEAR_MC_TYPE_MASK) || + pore_ORI( &ctx, D1, D1, BIT(60)) || + pore_MR( &ctx, P1, D1) || + PORE_LOCATION( &ctx, tgt2); + if (pgas_rc>0) { + MY_ERR("***setp1_mcreadand rc = %d", pgas_rc); + return pgas_rc; + } + pgas_rc = pore_inline_branch_fixup( &ctx, src1, tgt1) || + pore_inline_branch_fixup( &ctx, src2, tgt2); + if (pgas_rc>0) { + MY_ERR("***inline_branch_fixup rc = %d", pgas_rc); + return pgas_rc; + } +#else + uint32_t epmCID = 0x11; + pgas_rc = pore_LS(&ctx, P0, epmCID); //bits 2:7 get loaded to perv reg 26:31 + if (pgas_rc>0) { + MY_ERR("***LS rc = %d", pgas_rc); + return pgas_rc; + } +#endif + + pore_imm64b = ((uint64_t)i_scanSelectData) << 32; + pgas_rc = pore_STI(&ctx, scanSelectAddr, P0, pore_imm64b); + if (pgas_rc>0) { + MY_ERR("***STI rc = %d", pgas_rc); + return pgas_rc; + } + + // Preload the scan data/shift reg with the scan header check word. + // + pore_imm64b = ((uint64_t)scanRingCheckWord) << 32; + pgas_rc = pore_LI(&ctx, D0, pore_imm64b ); + if (pgas_rc > 0) { + MY_ERR("***(1)LI D0 rc = %d", pgas_rc); + return pgas_rc; + } + pgas_rc = pore_STD(&ctx, D0, scanRing_baseAddr, P0); + if (pgas_rc > 0) { + MY_ERR("***STD D0 rc = %d", pgas_rc); + return pgas_rc; + } + + // Check how many 32-bit shift ops are needed and if we need final shift of remaining bit. + count = i_ringBitLen/32; + remainder = i_ringBitLen%32; + if (remainder >0) + count = count + 1; + + // From P7+: skip first 32 bits associated with FSI engine + //TODO: check with perv design team if FSI 32 bit assumption is still valid in p8 + //remainingBits=i_ringBitLen-32; + // CMO: I changed the following to not skip the first 32-bit. + //remainingBits = i_ringBitLen-32; //Yong impl. + remainingBits = i_ringBitLen; //Mike impl. + + MY_DBG("count=%i rem=%i remBits=%i",count,remainder,remainingBits); + + // Compare 32 bit data at a time then shift ring (p7+ reqmt) + // TODO: check if p8 still requires skipping the 1st 32 bit + + // Read and compare init and flush values 32 bits at a time. Store delta in o_delta buffer. + //for (i=1; i<count; i++) { //Yong impl + for (i=0; i<count; i++) { //Mike impl + + //==================================================================================== + // If flush & init values are identical, increase the read count, no code needed. + // When the discrepancy is found, read (rotate the ring) up to current address + // then scan/write in the last 32 bits + //==================================================================================== + // TODO: add polling routine and change the max ring to 65535? Need to check with HW team + // Note: For PORE scan instruction, set Port to 3. Bit 16 Must be set to 1. + + if (i_deltaRing[i] > 0) { + + if (rotateLen > 0) { + //-------------------------------------------------------------------------- + // Rotate scan ring by the current rotate length + // rotate length is equivalent to current rotate addr - previous rotate addr + // + // Note space overflow is checked by inline assembler in P8 + // TODO: Not useing SCR1RDA : check with perv team + // TODO: what to do with 1st 32 bit for FSI?? + //-------------------------------------------------------------------------- + //CMO: This addr calc only works if baseAddr=0 in those bits where rotateLen=1? + scanRing_poreAddr=scanRing_baseAddr | rotateLen; + + MY_DBG("base addr = 0x8%x, pore addr = 0x8%x, rotatelen = %d", scanRing_baseAddr, scanRing_poreAddr, rotateLen); + + //SCR1RD: shift out then read + pgas_rc=pore_LD(&ctx, D0, scanRing_poreAddr, P0); + if (pgas_rc > 0) { + MY_ERR("***LD D0 rc = %d", pgas_rc); + return pgas_rc; + } + + } // End of if (rotateLen>0) + + // If the rotate length is <= 32, rotate by 32 or remaining bits if len <32 + if (remainingBits>32) + scanRing_poreAddr = scanRing_baseAddr | 32; + else + scanRing_poreAddr = scanRing_baseAddr | remainingBits; + + //LI : Load XORed value to Scratch 1 reg. (same as p7+) + //TODO: Check why not overwrite with init values? + pore_imm64b = ((uint64_t)i_deltaRing[i]) << 32; + + pgas_rc = pore_LI(&ctx, D0, pore_imm64b ); + if (pgas_rc > 0) { + MY_ERR("***(2)LI D0 rc = %d", pgas_rc); + return pgas_rc; + } + + pgas_rc = pore_STD(&ctx, D0, scanRing_poreAddr, P0); + if (pgas_rc > 0) { + MY_ERR("***STD D0 rc = %d", pgas_rc); + return pgas_rc; + } + + rotateLen=0; //reset rotate length + } + else { + // OK, so i_deltaRing==0 (init and alter states are identical) + // Increase rotate length by remaining scan bits (32 by default) + // TODO : the max rotate ring size needs to be modified. + // there will be no size limit, but will add polling once the feture is available + + // Increase rotate length by remaining scan bits (default 32 bits) + if (remainingBits>32) + rotateLen = rotateLen + 32; + else + rotateLen = rotateLen + remainingBits; + + // This section will be modfied + // PORE does not release PIB/PCB until CC acks, thus limiting bandwidth + // It will time out if more than 4095 bits need to be rotated + // If rotate length is more than 4032 (allows to rotate up to 4064 bits + // Rotate the chain and reset rotate length counter + if (rotateLen>0xFC0) { + scanRing_poreAddr = scanRing_baseAddr | rotateLen; + pgas_rc = pore_LD(&ctx, D0, scanRing_poreAddr, P0); + if (pgas_rc > 0) { + MY_ERR("***LD D0 rc = %d", pgas_rc); + return pgas_rc; + } + + rotateLen=0; + } //end of if (roateLen >0xFC0) + + } //end of else (i_deltaRing==0) + + if (remainingBits>32) + remainingBits = remainingBits - 32; + else + remainingBits = 0; + + } // End of for loop + + // If the scan ring has not been rotated to the original position + // shift the ring by remaining shift bit length + if (rotateLen>0) { + scanRing_poreAddr=scanRing_baseAddr | rotateLen; + pgas_rc = pore_LD(&ctx, D0, scanRing_poreAddr, P0); + if (pgas_rc > 0) { + MY_ERR("***LD D0 rc = %d", pgas_rc); + return pgas_rc; + } + rotateLen=0; + } + + // Finally, check that our header check word went through in one piece. + // + // Load the output check word... + pgas_rc = pore_LD(&ctx, D0, scanRing_baseAddr, P0) | + // Compare against the reference header check word... + pore_XORI( &ctx, D0, D0, ((uint64_t)scanRingCheckWord) << 32) | + // For now, branch to HALT instruction if not equal, otherwise return in the following instruction... + // But eventually branch to firmware error_handler if not equal + // pore_BRANZ(&ctx, D0, error_handler) || + PORE_LOCATION( &ctx, src3) | +// pore_BRANZ( &ctx, D0, ctx.lc+8) || // Jump two 4-byte instr (incl this one) to get to HALT. + pore_BRANZ( &ctx, D0, tgt3) | // Jump two 4-byte instr (incl this one) to get to HALT. + pore_RET( &ctx) | + PORE_LOCATION( &ctx, tgt3) | + pore_HALT( &ctx); + if (pgas_rc > 0) { + MY_ERR("***LD, XORI, BRANZ, RET or HALT went wrong rc = %d", pgas_rc); + return pgas_rc; + } + pgas_rc = pore_inline_branch_fixup( &ctx, src3, tgt3); + if (pgas_rc>0) { + MY_ERR("***inline_branch_fixup rc = %d", pgas_rc); + return pgas_rc; + } + + osIndex = ctx.lc/4; + *o_wfInlineLenInWords = osIndex; + + return rc; +} + + + +// write_wiggle_flip_to_image() +// 1 - mmap input image, +// 2 - Compose delta binary buffer containing RS4 launcher + RS4 delta data, +// 3 - Append delta buffer to .initf section. +// 4 - Save new image to output image file. +int write_wiggle_flip_to_image( void *io_imageOut, + uint32_t *i_sizeImageMaxNew, + DeltaRingLayout *i_ringLayout, + uint32_t *i_wfInline, + uint32_t i_wfInlineLenInWords) +{ + uint32_t rc=0, bufLC; + uint32_t sizeImageIn, sizeNewDataBlock; + uint32_t sizeImageOutThisEst=0, sizeImageOutThis=0; + void *initfBuffer=NULL; + uint32_t ringRingsOffset=0; + uint64_t ringPoreAddress=0,backPtr=0,fwdPtr=0,fwdPtrCheck; + + SBE_XIP_ERROR_STRINGS(errorStrings); + + MY_DBG("wfInlineLenInWords=%i", i_wfInlineLenInWords); + + // Modify the input ring layout content + // - Remove the qualifier section: ddLevel, sysPhase, override and reserved1+2. This means + // reducing the entryOffset by the size of these qualifiers. + // - Adjust sizeOfThis + // - Use new wfInline member of ring layout struct. + // - Ignore the rs4Delta member + // + // For sizeOfThis, we must ensure 4-byte alignment WF code. That is easy since both entryOffset + // and wfInlineLenInWord are already word-aligned. + // + i_ringLayout->entryOffset = myRev64( myRev64(i_ringLayout->entryOffset) - + sizeof(i_ringLayout->ddLevel) - + sizeof(i_ringLayout->sysPhase) - + sizeof(i_ringLayout->override) - + sizeof(i_ringLayout->reserved1) - + sizeof(i_ringLayout->reserved2) ); + i_ringLayout->sizeOfThis = myRev32( myRev64(i_ringLayout->entryOffset) + + i_wfInlineLenInWords*4 ); + // Not really any need for this. Just being consistent. Once we have transitioned completely to new + // headers, then ditch i_wfInline from parm list and assign wfInline to layout in main program. + i_ringLayout->wfInline = i_wfInline; + + if (((uintptr_t)i_ringLayout)%4 || myRev64(i_ringLayout->entryOffset)%4) { + MY_ERR("ERROR : Ring layout is not word-aligned."); + return IMGBUILD_ERR_MISALIGNED_RING_LAYOUT; + } + + // Calc the size of the data section we're adding and the resulting output image. + // + rc = sbe_xip_image_size( io_imageOut, &sizeImageIn); + if (rc) { + MY_ERR("ERROR : sbe_xip_image_size() failed: %s", SBE_XIP_ERROR_STRING(errorStrings, rc)); + return IMGBUILD_ERR_XIP_MISC; + } + sizeNewDataBlock = myRev32(i_ringLayout->sizeOfThis); + // ...estimate max size of new image + sizeImageOutThisEst = sizeImageIn + sizeNewDataBlock + SBE_XIP_MAX_SECTION_ALIGNMENT; // + + if (sizeImageOutThisEst>*i_sizeImageMaxNew) { + MY_ERR("ERROR : Estimated new image size (=%i) would exceed max allowed size (=%i).", + sizeImageOutThisEst, *i_sizeImageMaxNew); + *i_sizeImageMaxNew = sizeImageOutThisEst; + return IMGBUILD_ERR_IMAGE_TOO_LARGE; + } + + MY_DBG("Input image size\t\t= %6i\n\tNew initf data block size\t= %6i\n\tOutput image size\t\t<=%6i", + sizeImageIn, sizeNewDataBlock, sizeImageOutThisEst); + MY_DBG("entryOffset = %i\n\tsizeOfThis = %i\n\tMeta data size = %i", + (uint32_t)myRev64(i_ringLayout->entryOffset), myRev32(i_ringLayout->sizeOfThis), myRev32(i_ringLayout->sizeOfMeta)); + MY_DBG("Back item ptr = 0x%016llx",myRev64(i_ringLayout->backItemPtr)); + MY_DBG("DD level = %i\n\tSys phase = %i\n\tOverride = %i\n\tReserved1+2 = %i", + myRev32(i_ringLayout->ddLevel), i_ringLayout->sysPhase, i_ringLayout->override, i_ringLayout->reserved1|i_ringLayout->reserved2); + + // Combine rs4RingLayout members into a unified buffer (initfBuffer). + // + initfBuffer = malloc((size_t)sizeNewDataBlock); + if (initfBuffer == NULL) { + MY_ERR("ERROR : malloc() of initf buffer failed."); + return IMGBUILD_ERR_MEMORY; + } + // ... and copy the WF ring layout content into initfBuffer in BIG-ENDIAN format. + bufLC = 0; + memcpy( (uint8_t*)initfBuffer+bufLC, &i_ringLayout->entryOffset, (uintptr_t)&i_ringLayout->metaData-(uintptr_t)&i_ringLayout->entryOffset); + bufLC = (uintptr_t)&i_ringLayout->metaData-(uintptr_t)&i_ringLayout->entryOffset; + memcpy( (uint8_t*)initfBuffer+bufLC, i_ringLayout->metaData, myRev32(i_ringLayout->sizeOfMeta)); + + bufLC = (uint32_t)myRev64(i_ringLayout->entryOffset); + // The above forces word-alignment of bufLC as [previous] metaData member is only byte aligned. + memcpy( (uint8_t*)initfBuffer+bufLC, i_wfInline, i_wfInlineLenInWords*4); + + // Append WF ring layout to .rings section of in-memory input image. + // Note! All layout members should already be 4-byte-aligned. + // + rc = sbe_xip_append( io_imageOut, + SBE_XIP_SECTION_RINGS, + (void*)initfBuffer, + sizeNewDataBlock, + sizeImageOutThisEst, + &ringRingsOffset); + MY_DBG("ringRingsOffset=0x%08x",ringRingsOffset); + if (rc) { + MY_ERR("ERROR : sbe_xip_append() failed: %s", SBE_XIP_ERROR_STRING(errorStrings, rc)); + if (initfBuffer) free(initfBuffer); + return IMGBUILD_ERR_XIP_MISC; + } + // ...get new image size, update return size, and test if successful update. + sbe_xip_image_size( io_imageOut, &sizeImageOutThis); + MY_DBG("Output image size (final)\t=%i",sizeImageOutThis); + *i_sizeImageMaxNew = sizeImageOutThis; + rc = sbe_xip_validate( io_imageOut, sizeImageOutThis); + if (rc) { + MY_ERR("ERROR : sbe_xip_validate() of output image failed: %s", SBE_XIP_ERROR_STRING(errorStrings, rc)); + if (initfBuffer) free(initfBuffer); + return IMGBUILD_ERR_XIP_MISC; + } + MY_DBG("Successful append of RS4 ring to .rings. Next, update forward ptr..."); + + // Update forward pointer associated with the ring/var name + any override offset. + // + // Convert the ring offset (wrt .rings address) to an PORE address + rc = sbe_xip_section2pore(io_imageOut, SBE_XIP_SECTION_RINGS, ringRingsOffset, &ringPoreAddress); + fwdPtr = ringPoreAddress; + MY_DBG("fwdPtr=0x%016llx", fwdPtr); + if (rc) { + MY_ERR("ERROR : sbe_xip_section2pore() failed: %s", SBE_XIP_ERROR_STRING(errorStrings, rc)); + if (initfBuffer) free(initfBuffer); + return IMGBUILD_ERR_XIP_MISC; + } + // ...then update the forward pointer, i.e. the old "variable/ring name's" pointer. + // DO NOT add any 8-byte offset if override ring. The backItemPtr already has this + // from p8_delta_scan. + // + backPtr = myRev64(i_ringLayout->backItemPtr); + MY_DBG("backPtr = 0x%016llx", backPtr); + rc = sbe_xip_write_uint64( io_imageOut, + backPtr, + fwdPtr); + rc = rc+sbe_xip_read_uint64(io_imageOut, + backPtr, + &fwdPtrCheck); + if (rc) { + MY_ERR("ERROR : sbe_xip_[write,read]_uint64() failed: %s", SBE_XIP_ERROR_STRING(errorStrings, rc)); + if (initfBuffer) free(initfBuffer); + return IMGBUILD_ERR_XIP_MISC; + } + if (fwdPtrCheck!=ringPoreAddress || backPtr!=myRev64(i_ringLayout->backItemPtr)) { + MY_ERR("ERROR : Forward or backward pointer mess. Check code."); + MY_ERR("fwdPtr =0x%016llx",fwdPtr); + MY_ERR("fwdPtrCheck =0x%016llx",fwdPtrCheck); + MY_ERR("layout bckPtr=0x%016llx",myRev64(i_ringLayout->backItemPtr)); + MY_ERR("backPtr =0x%016llx",backPtr); + if (initfBuffer) free(initfBuffer); + return IMGBUILD_ERR_FWD_BACK_PTR_MESS; + } + // ...test if successful update. + rc = sbe_xip_validate( io_imageOut, sizeImageOutThis); + if (rc) { + MY_ERR("ERROR : sbe_xip_validate() of output image failed: %s", SBE_XIP_ERROR_STRING(errorStrings, rc)); + MY_ERR("Probable cause:"); + MY_ERR("\tsbe_xip_write_uint64() updated at the wrong address (=0x%016llx)", + myRev64(i_ringLayout->backItemPtr)); + if (initfBuffer) free(initfBuffer); + return IMGBUILD_ERR_XIP_MISC; + } + + if (initfBuffer) free(initfBuffer); + + return rc; +} + + + +// append_empty_section() +int append_empty_section( void *io_image, + uint32_t *i_sizeImageMaxNew, + uint32_t i_sectionId, + uint32_t i_sizeSection) +{ + uint32_t rc=0; + uint32_t sizeImageIn=0, sizeImageOutThis=0, sizeImageOutThisEst=0; + uint32_t offsetCheck=1; + void *bufEmpty=NULL; + + SBE_XIP_ERROR_STRINGS(errorStrings); + + rc = 0; + + if (i_sizeSection==0) { + MY_INF("INFO : Requested append size = 0. Nothing to do."); + return rc; + } + + // Check if there is enough room in the new image to add section. + // + sbe_xip_image_size( io_image, &sizeImageIn); + // ...estimate max size of new image + sizeImageOutThisEst = sizeImageIn + i_sizeSection + SBE_XIP_MAX_SECTION_ALIGNMENT; + if (sizeImageOutThisEst>*i_sizeImageMaxNew) { + MY_ERR("ERROR : Estimated new image size (=%i) would exceed max allowed size (=%i).", + sizeImageOutThisEst, *i_sizeImageMaxNew); + *i_sizeImageMaxNew = sizeImageOutThisEst; + return IMGBUILD_ERR_IMAGE_TOO_LARGE; + } + + // Add the 0-initialized buffer as a section append. + // + bufEmpty = calloc( i_sizeSection, 1); + rc = sbe_xip_append( io_image, + i_sectionId, + bufEmpty, + i_sizeSection, + sizeImageOutThisEst, + &offsetCheck); + if (rc) { + MY_ERR("ERROR : xip_append() failed: %s\n",SBE_XIP_ERROR_STRING(errorStrings, rc)); + if (bufEmpty) + free(bufEmpty); + return DSLWB_SLWB_IMAGE_ERROR; + } + if (offsetCheck) + MY_INF("INFO : Section was not empty at time of xip_append(). It contained %i bytes.",offsetCheck); + // ...get new image size, update return size, and test if successful update. + sbe_xip_image_size( io_image, &sizeImageOutThis); + MY_DBG("Output image size (final)\t=%i",sizeImageOutThis); + *i_sizeImageMaxNew = sizeImageOutThis; + rc = sbe_xip_validate( io_image, sizeImageOutThis); + if (rc) { + MY_ERR("ERROR : xip_validate() of output image failed: %s", SBE_XIP_ERROR_STRING(errorStrings, rc)); + if (bufEmpty) free(bufEmpty); + return IMGBUILD_ERR_XIP_MISC; + } + + if (bufEmpty) + free(bufEmpty); + + return rc; +} + + + +void cleanup( void *buf1, + void *buf2, + void *buf3, + void *buf4, + void *buf5) +{ + if (buf1) free(buf1); + if (buf2) free(buf2); + if (buf3) free(buf3); + if (buf4) free(buf4); + if (buf5) free(buf5); +} + + +} diff --git a/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_api.h b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_api.h new file mode 100644 index 000000000..0656f0a1c --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_api.h @@ -0,0 +1,283 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_api.h $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +/* $Id: p8_pore_api.h,v 1.2 2012/04/11 16:58:29 cmolsen Exp $ */ +/* $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/utils/p8_pore_api.h,v $ */ +/*------------------------------------------------------------------------------*/ +/* *! (C) Copyright International Business Machines Corp. 2010 */ +/* *! All Rights Reserved -- Property of IBM */ +/* *! *** IBM Confidential *** */ +/*------------------------------------------------------------------------------*/ +/* *! TITLE p8_pore_api */ +/* *! DESCRIPTION : PORE APIs */ +/* *! OWNER NAME : Nicole Schwartz Email: nschwart@us.ibm.com */ +/* *! BACKUP NAME : */ +/* *! ADDITIONAL COMMENTS : */ + +/*------------------------------------------------------------------------------*/ +/* Don't forget to create CVS comments when you check in your changes! */ +/*------------------------------------------------------------------------------*/ + +#ifndef _P8P_PORE_API_H +#define _P8P_PORE_API_H + +/** + * Contains all external APIs used by firmware to generate/modify the P7+ + * PORE image. + */ + + +#include "p8_pore_api_custom.h" +/*#include <p7p_pore_image.h>*/ +#include "p8_pore_api_const.h" + +typedef struct { + char ringName[50]; + uint32_t ringAddress; + uint32_t clockControlData; + uint32_t length; +} p8_pore_ringInfoStruct; + + +/** + * Generate a set of PORE instructions that will initialize a scan ring. + * + * @param i_ringAddr host Address of scan ring + * @param i_ringBitLen host Number of bits in the scan ring + * @param i_ring host Pointer to initialized ring data, left-aligned binary + * @param i_flush host Pointer to ring data for flush state, left-aligned binary + * @param i_maxStreamLenInWords host Max space available for resulting PORE image in 32-bit words + * @param o_streamLenInWords host Actual size of PORE image in 32-bit words + * @param o_streamOutput BigEndian Pointer to allocated local memory to write PORE image into, this is + * the location to write the ring data into + * + * @return uint32_t Error return codes + * P8_PORE_SUCCESS_RC : No errors + * P8_PORE_IMAGE_TOO_BIG_RC : size of PORE image exceeded allowed space + * P8_PORE_XXX_RC : other errors... + */ +uint32_t p8_pore_gen_scan( uint32_t i_ringAddr, + uint32_t i_ringBitLen, + uint32_t* i_ring, + uint32_t* i_flush, + uint32_t i_maxStreamLenInWords, + uint32_t* o_streamLenInWords, + uint32_t* o_streamOutput ); + +/** + * Generate or update a set of PORE instructions that will initialize a scom register. + * + * @param i_scomAddr host Address of scom register + * @param i_scomData host Two 32-bit words of scom register data + * @param i_operation host Should data be appended or existing data updated + * P8_PORE_SCOM_APPEND : add scom instructions to the end of the existing image + * P8_PORE_SCOM_OR : overlay scom data onto existing instruction by bitwise OR + * P8_PORE_SCOM_AND : overlay scom data onto existing instruction by bitwise AND + * P8_PORE_SCOM_REPLACE : replace existing instructions with new data + * P8_PORE_SCOM_NOOP : replace existing instructions with NOOP, i_scomData is junk + * @param i_maxStreamLenInWords host Max space available for resulting PORE image in 32-bit words + * @param o_streamOutput BigEndian Pointer to allocated local memory to write PORE image into + * + * @return uint32_t Error return codes + * P8_PORE_SUCCESS_RC : No errors + * P8_PORE_IMAGE_TOO_BIG_RC : size of PORE image exceeded allowed space + * P8_PORE_BAD_ARG_RC : some input argument is nonsensical + * P8_PORE_ADDR_NOT_FOUND : could not find existing scom for overlay (AND/OR) operation + * P8_PORE_XXX_RC : other errors... + */ +uint32_t p8_pore_gen_scom( uint32_t i_scomAddr, + uint32_t i_scomData[2], + uint32_t i_operation, + uint32_t i_maxStreamLenInWords, + uint32_t* o_streamOutput ); + +/** + * Generate or update a set of PORE instructions that will initialize an + * architected register in the processor, ie. SPR or GPR. It is assumed that + * all updates will replace any existing data for that register. If the data + * does not already exist then it will be appended. + * + * @param i_regName host Constant that determines which SPR to write (see p8_pore_const.h) + * @param i_regData host Two 32-bit words of register data + * @param i_coreIndex host Core to operate on + * @param i_threadIndex host Thread to operate on, used for HSPRG0 and LPCR + * @param i_maxStreamLenInWords host Max space available for resulting PORE image in 32-bit words + * @param o_streamOutput BigEndian Pointer to allocated local memory to write PORE image into + * + * @return uint32_t Error return codes + * P8_PORE_SUCCESS_RC : No errors + * P8_PORE_IMAGE_TOO_BIG_RC : size of PORE image exceeded allowed space + * P8_PORE_XXX_RC : other errors... + */ +uint32_t p8_pore_gen_cpureg( uint32_t i_regName, + uint32_t i_regData[2], + uint32_t i_coreIndex, + uint32_t i_threadIndex, + uint32_t i_maxStreamLenInWords, + uint32_t* o_streamOutput ); + +/** + * Generate a set of PORE instructions that will perform a branch operation + * to a relative address offset + * + * @param i_offset host Relative offset to branch to + * @param i_maxStreamLenInWords host Max space available for resulting PORE instruction(s) in 32-bit words + * @param i_branchType host Set to 0 for relative branch (BRA), set to 1 for branch to subroutine (BSR) + * @param o_streamLenInWords host Actual size of PORE instruction(s) in 32-bit words + * @param o_streamOutput BigEndian Pointer to allocated local memory to write PORE image into + * + * @return uint32_t Error return codes + * P8_PORE_SUCCESS_RC : No errors + * P8_PORE_IMAGE_TOO_BIG_RC : size of PORE image exceeded allowed space + * P8_PORE_XXX_RC : other errors... + */ +uint32_t p8_pore_gen_relbranch( uint32_t i_offset, + uint32_t i_maxStreamLenInWords, + uint32_t i_branchType, + uint32_t* o_streamLenInWords, + uint32_t* o_streamOutput ); + +/** + * Generate a set of PORE instructions that will perform a branch operation + * to an absolute address. + * + * @param i_address host Absolute address to branch to + * @param i_maxStreamLenInWords host Max space available for resulting PORE instruction(s) in 32-bit words + * @param o_streamLenInWords host Actual size of PORE instruction(s) in 32-bit words + * @param o_streamOutput host Pointer to allocated local memory to write PORE image into + * + * @return uint32_t Error return codes + * P8_PORE_SUCCESS_RC : No errors + * P8_PORE_IMAGE_TOO_BIG_RC : size of PORE image exceeded allowed space + * P8_PORE_XXX_RC : other errors... + */ +uint32_t p8_pore_gen_absbranch( uint32_t i_address, + uint32_t i_maxStreamLenInWords, + uint32_t* o_streamLenInWords, + uint32_t* o_streamOutput ); + +/** + * Generate a set of PORE instructions that are invalid and will cause an + * error. It is used to populate a region of memory that the PORE shouldn't + * execute. + * + * @param i_maxStreamLenInWords host Max space available for resulting PORE instruction(s) in 32-bit words + * @param o_streamOutput BigEndian Pointer to allocated local memory to write PORE image into + * + * @return uint32_t Error return codes + * P8_PORE_SUCCESS_RC : No errors + * P8_PORE_IMAGE_TOO_BIG_RC : size of PORE image exceeded allowed space + * P8_PORE_XXX_RC : other errors... + */ +uint32_t p8_pore_fill_invalid( uint32_t i_maxStreamLenInWords, + uint32_t* o_streamOutput ); + +/** + * Generate a set of PORE instructions that are return statements. It is used + * to populate a region of memory that the PORE should return from. + * + * @param i_maxStreamLenInWords host Max space available for resulting PORE instruction(s) in 32-bit words + * @param o_streamOutput BigEndian Pointer to allocated local memory to write PORE image into + * + * @return uint32_t Error return codes + * P8_PORE_SUCCESS_RC : No errors + * P8_PORE_IMAGE_TOO_BIG_RC : size of PORE image exceeded allowed space + * P8_PORE_XXX_RC : other errors... + */ +uint32_t p8_pore_fill_return( uint32_t i_maxStreamLenInWords, + uint32_t* o_streamOutput ); + +/** + * Generate a WAIT PORE instruction. + * + * @param i_wait host Number of pcb_nclk cycles to wait + * @param i_maxStreamLenInWords host Max space available for resulting PORE instruction(s) in 32-bit words + * @param o_streamLenInWords host Actual size of PORE instruction(s) in 32-bit words + * @param o_streamOutput BigEndian Pointer to allocated local memory to write PORE image into + * + * @return uint32_t Error return codes + * P8_PORE_SUCCESS_RC : No errors + * P8_PORE_IMAGE_TOO_BIG_RC : size of PORE image exceeded allowed space + * P8_PORE_XXX_RC : other errors... + */ +uint32_t p8_pore_gen_wait( uint32_t i_wait, + uint32_t i_maxStreamLenInWords, + uint32_t* o_streamLenInWords, + uint32_t* o_streamOutput ); + + +#endif /* _P8_PORE_H */ + +/* +*************** Do not edit this area *************** +This section is automatically updated by CVS when you check in this file. +Be sure to create CVS comments when you commit so that they can be included here. + +$Log: p8_pore_api.h,v $ +Revision 1.2 2012/04/11 16:58:29 cmolsen +Removed #define of __PORE_INLINE_ASSEMBLER_C__ + +Revision 1.1 2011/08/25 12:28:04 yjkim +initial checkin + +Revision 1.8 2010/08/31 14:47:15 schwartz +Changed comments about scom operations to include SCOM in the name + +Revision 1.7 2010/08/30 23:27:16 schwartz +Added TRACE statements to include specified number of arguments +Defined branch type constants +Added constant for last scom op used to check if operation input to gen_scan is valid +Added mult spr error constant +Added p7p_pore_gen_wait API +Changed additional C++ style comments to C style +Initialized all variables to 0 +Removed FTRACE statements +Added additional information to trace statements +Updated gen_scom to use the defined operation constants +Updated branch gen_relbranch to use defined branch type constants +Added rc check for calls to p7p_pore_gen_cpureg_status and p7p_pore_span_128byte_boundary subroutines + +Revision 1.6 2010/08/26 03:57:02 schwartz +Changed comments to C-style +Changed "" to <> for #includes +Moved RINGINFO struct and RINGINDEX constant into separate object file, includes created static_data.h file +Put p7p_pore in front of #defines +Removed ring length from ringInfoStruct +Renamed scom operators to have SCOM in the name +Fixed gen_scan to use SCANRD and SCANWR pore instructions +Fixed compiler warnings + +Revision 1.5 2010/07/01 21:42:11 schwartz +Included format (host or big endian) in parameter definitions + +Revision 1.4 2010/06/23 23:09:05 schwartz +Updated ordering of include statements so p7p_pore_api_custom.h is first +Updated definition of gen_cpureg to include coreIndex and threadIndex + +Revision 1.3 2010/05/24 02:32:07 schwartz +Fixed errors that appear when using -Werrors flag +Added in cvs logging (hopefully) + + +*/ + diff --git a/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_api_const.h b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_api_const.h new file mode 100644 index 000000000..43a2a3e5c --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_api_const.h @@ -0,0 +1,127 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_api_const.h $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +/* $Id: p8_pore_api_const.h,v 1.1 2011/08/25 12:32:33 yjkim Exp $ */ +/* $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/utils/p8_pore_api_const.h,v $ */ + +/** + * Contains any constants uses as inputs or outputs to the p7p_pore functions + */ + + +/****************************/ +/***** SCOM Operators *****/ +/****************************/ +#define P8_PORE_SCOM_APPEND 0 /* add scom instructions to the end of the existing image */ +#define P8_PORE_SCOM_REPLACE 1 /* replace existing instructions with new data */ +#define P8_PORE_SCOM_OR 2 /* overlay scom data onto existing instruction by bitwise OR */ +#define P8_PORE_SCOM_AND 3 /* overlay scom data onto existing instruction by bitwise AND */ +#define P8_PORE_SCOM_NOOP 4 /* replace existing instructions with NOP */ +#define P8_PORE_SCOM_LAST_OP 4 /* keep track of the last op for checking correctness of op input */ + + +/***************************/ +/***** CPU Registers *****/ +/***************************/ +#define P8_PORE_HSPRG0 304 +#define P8_PORE_HRMOR 313 +#define P8_PORE_LPCR 318 +#define P8_PORE_HMEER 337 +#define P8_PORE_HID0 1008 +#define P8_PORE_HID1 1009 +#define P8_PORE_HID4 1012 +#define P8_PORE_HID5 1014 +#define P8_PORE_MSR 2000 + + +/****************************/ +/***** Branch Types *****/ +/****************************/ +#define P8_PORE_BRA_REL 0 /* generate relative branch instruction */ +#define P8_PORE_BRA_SUB 1 /* generate branch to subroutine instruction */ + + +/**************************/ +/***** Return Codes *****/ +/**************************/ +#define P8_PORE_SUCCESS_RC 0x00000000 /* Success, no errors */ +#define P8_PORE_IMAGE_TOO_BIG_RC 0x00000001 /* size of PORE image exceeded allowed space */ +#define P8_PORE_BAD_ARG_RC 0x00000002 /* some input argument is nonsensical */ +#define P8_PORE_NO_ADDR_FOUND_RC 0x00000003 /* address to overlay not found */ +#define P8_PORE_MULT_ADDR_FOUND_RC 0x00000004 /* address to replace/overlay found multiple times */ +#define P8_PORE_MULT_SPR_FOUND_RC 0x00000005 /* spr to add/replace found multiple times*/ +#define P8_PORE_BAD_RING_ADDR_RC 0x00000006 /* don't recognize the ring addr*/ + + +/* may need to include errors for 128byte_bound check and cpureg_status check */ +/*...etc...*/ + +/* +*************** Do not edit this area *************** +This section is automatically updated by CVS when you check in this file. +Be sure to create CVS comments when you commit so that they can be included here. + +$Log: p8_pore_api_const.h,v $ +Revision 1.1 2011/08/25 12:32:33 yjkim +initial checkin + +Revision 1.7 2010/11/03 19:13:16 schwartz +Added code to gen_cpureg to handle changes to MSR + +Revision 1.6 2010/08/30 23:27:16 schwartz +Added TRACE statements to include specified number of arguments +Defined branch type constants +Added constant for last scom op used to check if operation input to gen_scan is valid +Added mult spr error constant +Added p7p_pore_gen_wait API +Changed additional C++ style comments to C style +Initialized all variables to 0 +Removed FTRACE statements +Added additional information to trace statements +Updated gen_scom to use the defined operation constants +Updated branch gen_relbranch to use defined branch type constants +Added rc check for calls to p7p_pore_gen_cpureg_status and p7p_pore_span_128byte_boundary subroutines + +Revision 1.5 2010/08/26 15:13:34 schwartz +Fixed more C++ style comments to C style comments + +Revision 1.4 2010/08/26 03:57:02 schwartz +Changed comments to C-style +Changed "" to <> for #includes +Moved RINGINFO struct and RINGINDEX constant into separate object file, includes created static_data.h file +Put p7p_pore in front of #defines +Removed ring length from ringInfoStruct +Renamed scom operators to have SCOM in the name +Fixed gen_scan to use SCANRD and SCANWR pore instructions +Fixed compiler warnings + +Revision 1.3 2010/06/23 23:07:40 schwartz +Updated define statements for SPRs, constant values are actual SPR values from Book IV + +Revision 1.2 2010/05/24 02:33:14 schwartz +Fixed errors that appear when using -Werrors flag +Added in cvs logging (hopefully) + + +*/ + diff --git a/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_api_custom.h b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_api_custom.h new file mode 100644 index 000000000..a35fb1006 --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_api_custom.h @@ -0,0 +1,142 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_api_custom.h $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +/* $Id: p8_pore_api_custom.h,v 1.5 2012/05/22 21:25:21 cmolsen Exp $ */ +/* $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/utils/p8_pore_api_custom.h,v $ */ + +#include <stdint.h> /* for uint32_t */ +#include <stdio.h> /* for printf */ +#ifndef __HOSTBOOT_MODULE +#include <netinet/in.h> /* for htonl */ +#endif + +/** + * This file should be modified by users to appropriately handle some + * environment-specific operations. + */ + + +/*********************************/ +/***** Logging and Tracing *****/ +/*********************************/ +/** + * All tracing functions assume printf-style formatting + */ + +#ifndef __FAPI +/* Trace an informational message */ +#define P8_PORE_ITRACE0(msg) printf("PORE> INFO: " msg "\n"); +#define P8_PORE_ITRACE1(msg, arg0) printf("PORE> INFO: " msg "\n", arg0); + +/* Trace an error message */ +#define P8_PORE_ETRACE0(msg) printf("PORE> ERROR: " msg "\n"); +#define P8_PORE_ETRACE1(msg, arg0) printf("PORE> ERROR: " msg "\n", arg0); +#define P8_PORE_ETRACE2(msg, arg0, arg1) printf("PORE> ERROR: " msg "\n", arg0, arg1); +#define P8_PORE_ETRACE3(msg, arg0, arg1, arg2) printf("PORE> ERROR: " msg "\n", arg0, arg1, arg2); +#define P8_PORE_ETRACE4(msg, arg0, arg1, arg2, arg3) printf("PORE> ERROR: " msg "\n", arg0, arg1, arg2, arg3); +#define P8_PORE_ETRACE5(msg, arg0, arg1, arg2, arg3, arg4) printf("PORE> ERROR: " msg "\n", arg0, arg1, arg2, arg3, arg4); +#endif +/* Used for debug, Cronus/FW should leave these empty */ +#define P8_PORE_DTRACE0(msg) +#define P8_PORE_DTRACE1(msg, arg0) +#define P8_PORE_DTRACE2(msg, arg0, arg1) +#define P8_PORE_DTRACE3(msg, arg0, arg1, arg2) +#define P8_PORE_DTRACE4(msg, arg0, arg1, arg2, arg3) + +/****** Following is only used for debug purposes ******/ +/* FW/Cronus should NOT include this section */ +/* DTRACE - Print debug statements to command line */ +/* FTRACE - Print text PORE instructions of cpureg setup to DEBUG_FILE */ +/* +#define P8_PORE_DTRACE0(msg) printf("PORE> DEBUG: " msg "\n"); +#define P8_PORE_DTRACE1(msg, arg0) printf("PORE> DEBUG: " msg "\n", arg0); +#define P8_PORE_DTRACE2(msg, arg0, arg1) printf("PORE> DEBUG: " msg "\n", arg0, arg1); +#define P8_PORE_DTRACE3(msg, arg0, arg1, arg2) printf("PORE> DEBUG: " msg "\n", arg0, arg1, arg2); +#define P8_PORE_DTRACE4(msg, arg0, arg1, arg2, arg3) printf("PORE> DEBUG: " msg "\n", arg0, arg1, arg2, arg3); +*/ + +/**********************************/ +/***** Endian-ness Handling *****/ +/**********************************/ +/** + * Handle byte-swapping if necessary + */ + +/* Default to big-endian format on both sides */ +#define P8_PORE_HOST_TO_BIG32( bit32_int ) htonl(bit32_int) +#define P8_PORE_BIG32_TO_HOST( bit32_int ) ntohl(bit32_int) +#define P8_PORE_HOST_TO_BIG16( bit16_int ) htonl(bit16_int) +#define P8_PORE_BIG16_TO_HOST( bit16_int ) ntohl(bit16_int) + +/* +*************** Do not edit this area *************** +This section is automatically updated by CVS when you check in this file. +Be sure to create CVS comments when you commit so that they can be included here. + +$Log: p8_pore_api_custom.h,v $ +Revision 1.5 2012/05/22 21:25:21 cmolsen +Updated to remove FAPI tracing, which is not allowed in plain C files. + +Revision 1.4 2012/05/21 14:45:41 cmolsen +Updated to address Gerrit review II comments about printf() usage. + +Revision 1.3 2012/05/15 19:53:38 cmolsen +Updated to address Gerrit review comments: +- Hostboot doesn't support printf(). + +Revision 1.2 2012/04/13 16:45:32 cmolsen +Includes __HOSTBOOT_MODULE exclude of <netinit/in.h> + +Revision 1.1 2011/08/25 12:28:38 yjkim +initial check in + +Revision 1.10 2010/08/30 23:27:17 schwartz +Added TRACE statements to include specified number of arguments +Defined branch type constants +Added constant for last scom op used to check if operation input to gen_scan is valid +Added mult spr error constant +Added p7p_pore_gen_wait API +Changed additional C++ style comments to C style +Initialized all variables to 0 +Removed FTRACE statements +Added additional information to trace statements +Updated gen_scom to use the defined operation constants +Updated branch gen_relbranch to use defined branch type constants +Added rc check for calls to p7p_pore_gen_cpureg_status and p7p_pore_span_128byte_boundary subroutines + +Revision 1.9 2010/08/30 14:57:54 schwartz +Removed FTRACE and associated #define statements +Changed TRACE macros to multiple macros with specified number of args + +Revision 1.6 2010/08/26 15:13:34 schwartz +Fixed more C++ style comments to C style comments + +Revision 1.5 2010/06/23 23:06:37 schwartz +Defined additional trace functions to be used for debugging, not in FW or Cronus + +Revision 1.4 2010/05/24 02:34:07 schwartz +Fixed errors that appear when using -Werrors flag +Added in cvs logging (hopefully) + + +*/ diff --git a/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_static_data.c b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_static_data.c new file mode 100644 index 000000000..e1a8387c0 --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_static_data.c @@ -0,0 +1,118 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_static_data.c $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +/* $Id: p8_pore_static_data.c,v 1.1 2011/08/25 12:32:01 yjkim Exp $ */ +/* $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/utils/p8_pore_static_data.c,v $ */ +/*------------------------------------------------------------------------------*/ +/* *! (C) Copyright International Business Machines Corp. 2010 */ +/* *! All Rights Reserved -- Property of IBM */ +/* *! *** IBM Confidential *** */ +/*------------------------------------------------------------------------------*/ +/* *! TITLE p7p_pore_static_data */ +/* *! DESCRIPTION : Static data for PORE APIs */ +/* *! OWNER NAME : Nicole Schwartz Email: nschwart@us.ibm.com */ +/* *! BACKUP NAME : */ +/* *! ADDITIONAL COMMENTS : */ + +/*------------------------------------------------------------------------------*/ +/* Don't forget to create CVS comments when you check in your changes! */ +/*------------------------------------------------------------------------------*/ +/* HvPlic include needed for PHYP, must be first include */ +/*#include "HvPlicModule.H"*/ +#include "p8_pore_api_custom.h" +#include "p8_pore_api.h" +#include "p8_pore_static_data.h" + +/* Note: this info is a place holder until we get all other rings */ +const p8_pore_ringInfoStruct P8_PORE_RINGINFO[] = { + /*ring name ring local address scan region/type*/ + { "REPR_RING_C0", 0x00034A08, 0x48000080 }, + { "REPR_RING_C1", 0x00034A02, 0x48002000 }, + { "REPR_RING_C2", 0x00034A01, 0x48004000 }, + { "REPR_RING_C3", 0x00034A04, 0x48000800 }, + { "REPR_RING_C4", 0x00034A07, 0x48000100 }, + { "REPR_RING_C5", 0x00034A05, 0x48000400 }, + { "REPR_RING_C6", 0x00034A07, 0x48000100 }, + { "REPR_RING_C7", 0x00034A05, 0x48000400 }, + /* P7P data + { "EX_ECO_BNDY", 0x00034A08, 0x48000080 }, + { "EX_ECO_GPTR", 0x00034A02, 0x48002000 }, + { "EX_ECO_MODE", 0x00034A01, 0x48004000 }, + { "EX_ECO_LBST", 0x00034A04, 0x48000800 }, + { "EX_ECO_TIME", 0x00034A07, 0x4800010000000000 }, + { "EX_ECO_ABST", 0x00034A05, 0x4800040000000000 }, + { "EX_ECO_REGF", 0x00034A03, 0x4800100000000000 }, + { "EX_ECO_REPR", 0x00034A06, 0x4800020000000000 }, + { "EX_ECO_FUNC", 0x00034800, 0x4800800000000000 }, + { "EX_ECO_L3REFR", 0x00030200, 0x0200800000000000 }, + { "EX_ECO_DPLL_FUNC", 0x00030400, 0x0400800000000000 }, + { "EX_ECO_DPLL_GPTR", 0x00030402, 0x0400200000000000 }, + { "EX_ECO_DPLL_MODE", 0x00030401, 0x0400400000000000 }, + { "EX_CORE_BNDY", 0x00033008, 0x3000008000000000 }, + { "EX_CORE_GPTR", 0x00033002, 0x3000200000000000 }, + { "EX_CORE_MODE", 0x00033001, 0x3000400000000000 }, + { "EX_CORE_LBST", 0x00033004, 0x3000080000000000 }, + { "EX_CORE_TIME", 0x00033007, 0x3000010000000000 }, + { "EX_CORE_ABST", 0x00033005, 0x3000040000000000 }, + { "EX_CORE_REGF", 0x00032003, 0x2000100000000000 }, + { "EX_CORE_REPR", 0x00033006, 0x3000020000000000 }, + { "EX_CORE_FUNC", 0x00032000, 0x2000800000000000 }, + { "EX_CORE_L2FARY", 0x00031009, 0x1000900000000000 }, + */ +}; + +const int P8_PORE_RINGINDEX=sizeof P8_PORE_RINGINFO/sizeof P8_PORE_RINGINFO[0]; + +/* +*************** Do not edit this area *************** +This section is automatically updated by CVS when you check in this file. +Be sure to create CVS comments when you commit so that they can be included here. + +$Log: p8_pore_static_data.c,v $ +Revision 1.1 2011/08/25 12:32:01 yjkim +initial checkin + +Revision 1.5 2010/10/19 22:34:41 schwartz +added #include <p7p_pore_static_data.h> + +Revision 1.4 2010/08/26 15:13:33 schwartz +Fixed more C++ style comments to C style comments + +Revision 1.3 2010/08/26 03:57:02 schwartz +Changed comments to C-style +Changed "" to <> for #includes +Moved RINGINFO struct and RINGINDEX constant into separate object file, includes created static_data.h file +Put p7p_pore in front of #defines +Removed ring length from ringInfoStruct +Renamed scom operators to have SCOM in the name +Fixed gen_scan to use SCANRD and SCANWR pore instructions +Fixed compiler warnings + +Revision 1.2 2010/07/09 15:38:35 schwartz +Changed ring names to uppercase and updated length of rings. Neither of these pieces of data are used in the gen_scan API, but is used when generating rings for verification + +Revision 1.1 2010/06/23 23:10:06 schwartz +Moved constants ringInfoStruct and RINGINDEX into this file + + +*/ diff --git a/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_static_data.h b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_static_data.h new file mode 100644 index 000000000..dd18808b4 --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_static_data.h @@ -0,0 +1,72 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_static_data.h $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +/* $Id: p8_pore_static_data.h,v 1.1 2011/08/25 12:31:51 yjkim Exp $ */ +/* $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/utils/p8_pore_static_data.h,v $ */ +/*------------------------------------------------------------------------------*/ +/* *! (C) Copyright International Business Machines Corp. 2010 */ +/* *! All Rights Reserved -- Property of IBM */ +/* *! *** IBM Confidential *** */ +/*------------------------------------------------------------------------------*/ +/* *! TITLE p8_pore_static_data */ +/* *! DESCRIPTION : Static data for PORE APIs */ +/* *! OWNER NAME : Nicole Schwartz Email: nschwart@us.ibm.com */ +/* *! BACKUP NAME : */ +/* *! ADDITIONAL COMMENTS : */ +/* */ +/*------------------------------------------------------------------------------*/ +/* Don't forget to create CVS comments when you check in your changes! */ +/*------------------------------------------------------------------------------*/ + +#ifndef _P8_PORE_STATIC_DATA_H +#define _P8_PORE_STATIC_DATA_H + +extern const p8_pore_ringInfoStruct P8_PORE_RINGINFO[]; +extern const int P8_PORE_RINGINDEX; + +#endif /* _P8_PORE_STATIC_DATA_H */ + +/* +*************** Do not edit this area *************** +This section is automatically updated by CVS when you check in this file. +Be sure to create CVS comments when you commit so that they can be included here. + +$Log: p8_pore_static_data.h,v $ +Revision 1.1 2011/08/25 12:31:51 yjkim +initial check-in + +Revision 1.2 2010/08/26 15:13:34 schwartz +Fixed more C++ style comments to C style comments + +Revision 1.1 2010/08/26 03:57:02 schwartz +Changed comments to C-style +Changed "" to <> for #includes +Moved RINGINFO struct and RINGINDEX constant into separate object file, includes created static_data.h file +Put p7p_pore in front of #defines +Removed ring length from ringInfoStruct +Renamed scom operators to have SCOM in the name +Fixed gen_scan to use SCANRD and SCANWR pore instructions +Fixed compiler warnings + + +*/ diff --git a/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_table_gen_api.H b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_table_gen_api.H new file mode 100644 index 000000000..a99cbc99e --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_table_gen_api.H @@ -0,0 +1,168 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_pore_table_gen_api.H $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +/*------------------------------------------------------------------------------*/ +/* *! (C) Copyright International Business Machines Corp. 2012 */ +/* *! All Rights Reserved -- Property of IBM */ +/* *! *** IBM Confidential *** */ +/*------------------------------------------------------------------------------*/ +/* *! TITLE : p8_pore_table_gen_api */ +/* *! DESCRIPTION : Contains all external APIs used by firmware (PHYP) to */ +// generate/modify the P8 PORE SLW image. +/* *! OWNER NAME : Michael Olsen Email: cmolsen@us.ibm.com */ +/* *! ADDITIONAL COMMENTS : */ +// - Start file: p7p_pore_api.h +// - _table_entry structs must agree with Greg's proc_slw_ram.H +// +/*------------------------------------------------------------------------------*/ + +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> + +#include "pore_bitmanip.H" +#include "sbe_xip_image.h" + +//#ifndef _P8_PORE_API_H +//#define _P8_PORE_API_H + +//#include <p8_pore_api_custom.h> +//#include <p8_pore_image.h> +//#include <p8_pore_api_const.h> + +/* Common header for *.c and .S ramming code: Call it ../sbe/proc_slw_ram.H ? */ +// Header defs (P8&PORE 64-bit notation where bits are numbered from left-to-right) +#define RAM_HEADER_END_START 0 +#define RAM_HEADER_END_MASK BITS(RAM_HEADER_END_START,1) +#define RAM_HEADER_TYPE_START 2 +#define RAM_HEADER_TYPE_MASK BITS(RAM_HEADER_TYPE_START,2) +#define RAM_HEADER_SPRN_START 4 +#define RAM_HEADER_SPRN_MASK BITS(RAM_HEADER_SPRN_START,10) +#define RAM_HEADER_THREAD_START 16 +#define RAM_HEADER_THREAD_MASK BITS(RAM_HEADER_THREAD_START,3) +// MTSPR instr defs +#define RAM_MTSPR_INSTR_TEMPL ( ( (uint64_t)31<<(63-5) | (uint64_t)467<<(63-30) ) ) +#define RAM_MTSPR_SPR_START 11 +#define RAM_MTSPR_SPR_MASK BITS(RAM_MTSPR_SPR_START,10) +// Header defs (C notation where bits are numbered from right-to-left, and reducing to 32-bit) +#define RAM_HEADER_END_START_C ( 31-RAM_HEADER_END_START+1-1 ) +#define RAM_HEADER_END_MASK_C (uint32_t)(RAM_HEADER_END_MASK>>32) +#define RAM_HEADER_TYPE_START_C ( 31-RAM_HEADER_TYPE_START+1-2 ) +#define RAM_HEADER_TYPE_MASK_C (uint32_t)(RAM_HEADER_TYPE_MASK>>32) +#define RAM_HEADER_SPRN_START_C ( 31-RAM_HEADER_SPRN_START+1-10 ) +#define RAM_HEADER_SPRN_MASK_C (uint32_t)(RAM_HEADER_SPRN_MASK>>32) +#define RAM_HEADER_THREAD_START_C ( 31-RAM_HEADER_THREAD_START+1-3 ) +#define RAM_HEADER_THREAD_MASK_C (uint32_t)(RAM_HEADER_THREAD_MASK>>32) +// MTSPR instr defs +#define RAM_MTSPR_INSTR_TEMPL_C ( ( (uint32_t)31<<(31-5) | (uint32_t)467<<(31-30) ) ) +#define RAM_MTSPR_SPR_START_C ( 31-RAM_MTSPR_SPR_START+1-10 ) +//#define RAM_MTSPR_SPR_MASK_C (uint32_t)(BITS(RAM_MTSPR_SPR_START,10)>>32) +#define RAM_MTSPR_SPR_MASK_C (uint32_t)(RAM_MTSPR_SPR_MASK>>32) + +/* Other defs needed for ramming */ +// TOC names +#define SLW_HOST_REG_VECTOR_TOC_NAME "slw_host_reg_vector" +#define SLW_HOST_SCOM_VECTOR_TOC_NAME "slw_host_scom_vector" +#define SLW_HOST_REG_TABLE_TOC_NAME "slw_core_reg_table" + +// Defines for slw_build() to update "host_runtime_scome" w/pointer to "slw_host_runtime" at SLW image build time. +#define HOST_RUNTIME_SCOM_TOC_NAME "host_runtime_scom" // Null 1st, then fill w/addr of SLW_HOST_RUNTIME_TOC_NAME +#define SLW_HOST_RUNTIME_TOC_NAME "slw_host_runtime" + + +// RAM table defines +#define XIPSIZE_RAM_ENTRY ( (sizeof(RamTableEntry)+7)/8*8 ) +#define SLW_MAX_CORES 16 +#define SLW_MAX_CPUREGS_CORE 8 +#define SLW_MAX_CPUREGS_THREADS 3 +#define SLW_CORE_THREADS 8 +#define SLW_MAX_CPUREGS_OPS ( SLW_MAX_CPUREGS_CORE + \ + SLW_CORE_THREADS*SLW_MAX_CPUREGS_THREADS ) +#define SLW_SLW_SECTION_SIZE ( SLW_MAX_CORES * SLW_MAX_CPUREGS_OPS * XIPSIZE_RAM_ENTRY ) + +// Return codes +#define SLW_RAM_SUCCESS 0 +#define SLW_RAM_HEADERS_NOT_SYNCED 1 +#define SLW_RAM_IMAGE_SIZE_MISMATCH 2 +#define SLW_RAM_TABLE_ENTRY_OVERFLOW 3 +#define SLW_RAM_CODE_ERROR 4 +#define SLW_RAM_INVALID_PARAMETER 5 +#define SLW_RAM_WARNING_TABLE_CONTAMINATION 10 + +#ifdef __cpluscplus +extern "C" { +#endif + +typedef struct ram_instr_t { + uint32_t header; + uint32_t instr; + uint64_t data; +} RamTableEntry; + +// SLW supported SPR registers +typedef struct { + const char *name; + uint32_t value; + uint32_t swizzled; +} SlwSprRegs; + +const SlwSprRegs SLW_SPR_REGS[] = { + /* name value swizzled */ + // ...core regs + { "P8_SPR_HRMOR", 313, ( 313>>5 | ( 313&0x1f)<<5 ) }, + { "P8_SPR_HMEER", 337, ( 337>>5 | ( 337&0x1f)<<5 ) }, + { "P8_SPR_PMICR", 852, ( 852>>5 | ( 852&0x1f)<<5 ) }, + { "P8_SPR_PMCR", 884, ( 884>>5 | ( 884&0x1f)<<5 ) }, + { "P8_SPR_HID0", 1008, ( 1008>>5 | (1008&0x1f)<<5 ) }, + { "P8_SPR_HID1", 1009, ( 1009>>5 | (1009&0x1f)<<5 ) }, + { "P8_SPR_HID4", 1012, ( 1012>>5 | (1012&0x1f)<<5 ) }, + { "P8_SPR_HID5", 1014, ( 1014>>5 | (1014&0x1f)<<5 ) }, + // ...thread regs + { "P8_SPR_HSPRG0", 304, ( 304>>5 | ( 304&0x1f)<<5 ) }, + { "P8_SPR_LPCR", 318, ( 318>>5 | ( 318&0x1f)<<5 ) }, + // Greg, this is NOT in jbishop's SS. Got it from ur ST. But 1023 is max! + { "P8_SPR_MSR", 2000, ( 2000>>5 | (2000&0x1f)<<5 ) } +}; + +const int SLW_SPR_REGS_SIZE = sizeof(SLW_SPR_REGS)/sizeof(SLW_SPR_REGS[0]); + + +/* Name: p8_pore_gen_cpureg() + * Description: Populates ramming entries in the .slw section + * Parameter list: i_image - pointer to SLW mainstore image + * i_sizeImage - size of SLW mainstore image + * i_regName - unswizzled SPR register value + * i_regData - data to write to SPR register + * i_coreId - the core ID to operate on + * i_threadId - the thread ID to operate on + */ +uint32_t p8_pore_gen_cpureg(void *i_image, + uint32_t i_sizeImage, + uint32_t i_regName, + uint64_t i_regData, + uint32_t i_coreId, + uint32_t i_threadId); + +#ifdef __cpluscplus +} +#endif diff --git a/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_scan_compression.C b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_scan_compression.C new file mode 100644 index 000000000..1cf8f8f46 --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_scan_compression.C @@ -0,0 +1,600 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_scan_compression.C $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +// $Id: p8_scan_compression.C,v 1.3 2012/05/22 15:57:28 bcbrock Exp $ +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/utils/p8_scan_compression.C,v $ +//------------------------------------------------------------------------------ +// *! (C) Copyright International Business Machines Corp. 2011 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//------------------------------------------------------------------------------ +// *! OWNER NAME: Bishop Brock Email: Bishop Brock; bcbrock@us.ibm.com +// *! +// *! General Description: +// *! +// *! See below. +//------------------------------------------------------------------------------ +// +// Note: This file was originally named p8_scan_compression.c; See CVS archive +// for revision history of p8_scan_compression.c. + +/// \file p8_scan_compression.C +/// \brief APIs related to scan chain compression. +/// +/// RS4 Compression Format +/// ====================== +/// +/// Scan strings are compressed using a simple run-length encoding called +/// RS4. The string to be decompressed and scanned is the difference between +/// the current state of the ring and the desired final state of the ring. A +/// run-time optimization supports the case that the current state of the ring +/// is the flush state. +/// +/// Both the data to be compressed and the final compressed data are treated +/// as strings of 4-bit nibbles. When packaged in the scan data structure +/// however the compressed string must begin on an 8-byte boundary and is +/// always read 8 bytes at a time. In the scan data structure the compressed +/// strings are also padded with 0x0 nibbles to the next even multiple of 8 +/// bytes. The compressed string consists of control nibbles and data nibbles. +/// The string format includes a special control/data sequence that marks the +/// end of the string and the final bits of scan data. +/// +/// Runs of 0x0 nibbles (rotates) are encoded using a simple variable-length +/// integer encoding known as a "stop code". This code treats each nibble in +/// a variable-length integer encoding as an octal digit (the low-order 3 +/// bits) plus a stop bit (the high-order bit). The examples below +/// illustrate the encoding. +/// +/// 1xxx - Rotate 0bxxx nibbles (0 - 7) +/// 0xxx 1yyy - Rotate 0bxxxyyy nibbles (8 - 63) +/// 0xxx 0yyy 1zzz - Rotate 0bxxxyyyzzz nibbles (64 - 511) +/// etc. +/// +/// A 0-length rotate (code 0b1000) is needed to resynchronize the state +/// machine in the event of long scans (see below), or a string that begins +/// with a non-0x0 nibble. +/// +/// Runs of non-0x0 nibbles (scans) are inserted verbatim into the compressed +/// string after a control nibble indicating the number of nibbles of +/// uncompressed data. If a run is longer than 15 nibbles, the compression +/// algorithm must insert a 0-length rotate and a new scan-length control +/// before continuing with the non-0 data nibbles. +/// +/// xxxx - Scan 0bxxxx nibbles which follow, 0bxxxx != 0 +/// +/// The special case of a 0b0000 code where a scan count is expected marks the +/// end of the string. The end of string marker is always followed by a +/// nibble that contains the terminal bit count in the range 0-3. If the +/// length of the original binary string was not an even multiple of 4, then a +/// final nibble contains the final scan data left justified. +/// +/// 0000 00nn [ttt0] - Terminate 0bnn bits, data 0bttt0 if 0bnn != 0 +/// +/// +/// BNF Grammar +/// =========== +/// +/// Following is a BNF grammar for the strings accepted by the RS4 +/// decompression and scan algorithm. At a high level, the state machine +/// recognizes a series of 1 or more sequences of a rotate (R) followed by a +/// scan (S) or end-of-string marker (E), followed by the terminal count (T) +/// and optional terminal data (D). +/// +/// (R S)* (R E) T D? +/// +/// \code +/// +/// <rs4_string> ::= <rotate> <terminate> | +/// <rotate> <scan> <rs4_string> +/// +/// <rotate> ::= <octal_stop> | +/// <octal_go> <rotate> +/// +/// <octal_go> ::= '0x0' | ... | '0x7' +/// +/// <octal_stop> ::= '0x8' | ... | '0xf' +/// +/// <scan> ::= <scan_count(N)> <data(N)> +/// +/// <scan_count(N)> ::= * 0bnnnn, for N = 0bnnnn, N != 0 * +/// +/// <data(N)> ::= * N nibbles of uncompressed data * +/// +/// <terminate> ::= '0x0' <terminal_count(0)> | +/// '0x0' <terminal_count(T, T > 0)> <terminal_data(T)> +/// +/// <terminal_count(T)> ::= * 0b00nn, for T = 0bnn * +/// +/// <terminal_data(1)> ::= '0x0' | '0x8' +/// +/// <terminal_data(2)> ::= '0x0' | '0x4' | '0x8' | '0xc' +/// +/// <terminal_data(3)> ::= '0x0' | '0x2' | '0x4' | ... | '0xe' +/// +/// \endcode + + +#include <stdlib.h> +#include "p8_scan_compression.H" + +// Diagnostic aids for debugging +#ifdef DEBUG_P8_SCAN_COMPRESSION + +#ifdef __FAPI + +#include "fapi.H" +#define fprintf(stream, ...) FAPI_ERR(__VA_ARGS__) +#define BUG_NEWLINE "" + +#else // __FAPI + +#include <stdio.h> +#define BUG_NEWLINE "\n" + +#endif // __FAPI + +#define BUG(rc) \ + ({ \ + fprintf(stderr,"%s:%d : Trapped rc = %d" BUG_NEWLINE, \ + __FILE__, __LINE__, (rc)); \ + (rc); \ + }) + +#define BUGX(rc, ...) \ + ({ \ + BUG(rc); \ + fprintf(stderr, ##__VA_ARGS__); \ + (rc); \ + }) + +#else // DEBUG_P8_SCAN_COMPRESSION + +#define BUG(rc) (rc) +#define BUGX(rc, ...) (rc) + +#endif // DEBUG_P8_SCAN_COMPRESSION + +// Note: For maximum flexibility we provide private versions of +// endian-conversion routines rather than counting on a system-specific header +// to provide these. + +// Byte-reverse a 32-bit integer if on a little-endian machine + +static uint32_t +revle32(const uint32_t i_x) +{ + uint32_t rx; + +#ifndef _BIG_ENDIAN + uint8_t *pix = (uint8_t*)(&i_x); + uint8_t *prx = (uint8_t*)(&rx); + + prx[0] = pix[3]; + prx[1] = pix[2]; + prx[2] = pix[1]; + prx[3] = pix[0]; +#else + rx = i_x; +#endif + return rx; +} + + +#if COMPRESSED_SCAN_DATA_VERSION != 1 +#error This code assumes CompressedScanData structure version 1 layout +#endif + +void +compressed_scan_data_translate(CompressedScanData* o_data, + CompressedScanData* i_data) +{ + o_data->iv_magic = revle32(i_data->iv_magic); + o_data->iv_size = revle32(i_data->iv_size); + o_data->iv_algorithmReserved = revle32(i_data->iv_algorithmReserved); + o_data->iv_length = revle32(i_data->iv_length); + o_data->iv_scanSelect = revle32(i_data->iv_scanSelect); + o_data->iv_headerVersion = i_data->iv_headerVersion; + o_data->iv_flushOptimization = i_data->iv_flushOptimization; + o_data->iv_chipletId = i_data->iv_chipletId; +} + + +// Return a big-endian-indexed nibble from a byte string + +static int +get_nibble(const uint8_t* i_string, const uint32_t i_i) +{ + uint8_t byte; + int nibble; + + byte = i_string[i_i / 2]; + if (i_i % 2) { + nibble = byte & 0xf; + } else { + nibble = byte >> 4; + } + return nibble; +} + + +// Set a big-endian-indexed nibble in a byte string + +static int +set_nibble(uint8_t* io_string, const uint32_t i_i, const int i_nibble) +{ + uint8_t* byte; + + byte = &(io_string[i_i / 2]); + if (i_i % 2) { + *byte = (*byte & 0xf0) | i_nibble; + } else { + *byte = (*byte & 0x0f) | (i_nibble << 4); + } + return i_nibble; +} + + +// Encode an unsigned integer into a 4-bit octal stop code directly into a +// nibble stream at io_string<i_i>, returning the number of nibbles in the +// resulting code. + +static int +stop_encode(const uint32_t i_count, uint8_t* io_string, const uint32_t i_i) +{ + uint32_t count; + int digits, offset; + + // Determine the number of octal digits. There is always at least 1. + + count = i_count >> 3; + digits = 1; + while (count) { + count >>= 3; + digits++; + } + + // First insert the stop (low-order) digit + + offset = digits - 1; + set_nibble(io_string, i_i + offset, (i_count & 0x7) | 0x8); + + // Now insert the high-order digits + + count = i_count >> 3; + offset--; + while (count) { + set_nibble(io_string, i_i + offset, count & 0x7); + offset--; + count >>= 3; + } + + return digits; +} + + +// Decode an unsigned integer from a 4-bit octal stop code appearing in a byte +// string at i_string<i_i>, returning the number of nibbles decoded. + +static int +stop_decode(uint32_t* o_count, const uint8_t* i_string, const uint32_t i_i) +{ + int digits, nibble; + uint32_t i, count; + + digits = 0; + count = 0; + i = i_i; + + do { + nibble = get_nibble(i_string, i); + count = (count * 8) + (nibble & 0x7); + i++; + digits++; + } while ((nibble & 0x8) == 0); + + *o_count = count; + return digits; +} + + +// RS4 compression algorithm notes: +// +// RS4 compression processes i_string as a string of nibbles. Final +// special-case code handles the 0-3 remaining terminal bits. +// +// There is a special case for 0x0 nibbles embedded in a string of non-0x0 +// nibbles. It is more efficient to encode a single 0x0 nibble as part of a +// longer string of non 0x0 nibbles. However it is break-even (actually a +// slight statistical advantage) to break a scan seqeunce for 2 0x0 nibbles. +// +// If a run of 15 scan nibbles is found the scan is terminated and we return +// to the rotate state. Runs of more than 15 scans will always include a +// 0-length rotate between the scan sequences. +// +// Returns the number of nibbles in the compressed string. + +static uint32_t +_rs4_compress(CompressedScanData* o_data, + const uint8_t* i_string, + const uint32_t i_length) +{ + int state; /* 0 : Rotate, 1 : Scan */ + uint32_t n; /* Number of whole nibbles in i_data */ + uint32_t r; /* Number of reminaing bits in i_data */ + uint32_t i; /* Nibble index in i_string */ + uint32_t j; /* Nibble index in data */ + uint32_t k; /* Location to place scan count */ + uint32_t count; /* Counts rotate/scan nibbles */ + uint8_t* data; /* The compressed scan data area */ + + n = i_length / 4; + r = i_length % 4; + i = 0; + j = 0; + k = 0; /* Makes GCC happy */ + data = (uint8_t*)o_data + sizeof(CompressedScanData); + count = 0; + state = 0; + + // Process the bulk of the string. Note that state changes do not + // increment 'i' - the nibble at i_data<i> is always scanned again. + + while (i < n) { + if (state == 0) { + if (get_nibble(i_string, i) == 0) { + count++; + i++; + } else { + j += stop_encode(count, data, j); + count = 0; + k = j; + j++; + state = 1; + } + } else { + if (get_nibble(i_string, i) == 0) { + if (((i + 1) < n) && (get_nibble(i_string, i + 1) == 0)) { + set_nibble(data, k, count); + count = 0; + state = 0; + } else { + set_nibble(data, j, 0); + count++; + i++; + j++; + } + } else { + set_nibble(data, j, get_nibble(i_string, i)); + count++; + i++; + j++; + } + if ((state == 1) && (count == 15)) { + set_nibble(data, k, 15); + state = 0; + count = 0; + } + } + } + + // Finish the current state and insert the terminate code (scan 0). If we + // finish on a scan we must insert a null rotate first. + + if (state == 0) { + j += stop_encode(count, data, j); + } else { + set_nibble(data, k, count); + j += stop_encode(0, data, j); + } + set_nibble(data, j, 0); + j++; + + // Insert the remainder count nibble, and if non-0, the remainder data + // nibble. + + set_nibble(data, j, r); + j++; + if (r != 0) { + set_nibble(data, j, get_nibble(i_string, n)); + j++; + } + + // Return the number of nibbles in the compressed string. + + return j; +} + + +// The worst-case compression for RS4 requires 2 nibbles of control overhead +// per 15 nibbles of data (17/15), plus a maximum of 2 nibbles of termination. +// We always allocate this worst-case amount of memory including the header +// and any rounding required to guarantee that the allocated length is a +// multiple of 8 bytes. The final size is also rounded up to a multiple of 8 +// bytes. + +int +rs4_compress(CompressedScanData** o_data, + uint32_t* o_size, + const uint8_t* i_string, + const uint32_t i_length, + const uint64_t i_scanSelect, + const uint8_t i_chipletId, + const uint8_t i_flushOptimization) +{ + int rc; + uint32_t nibbles, bytes; + + nibbles = (((((i_length + 3) / 4) + 14) / 15) * 17) + 2; + bytes = ((nibbles + 1) / 2) + sizeof(CompressedScanData); + bytes = ((bytes + 7) / 8) * 8; + + *o_data = (CompressedScanData*)calloc(bytes, 1); + + if (*o_data == 0) { + rc = BUG(SCAN_COMPRESSION_NO_MEMORY); + } else { + nibbles = _rs4_compress(*o_data, i_string, i_length); + bytes = ((nibbles + 1) / 2) + sizeof(CompressedScanData); + bytes = ((bytes + 7) / 8) * 8; + + (*o_data)->iv_magic = revle32(RS4_MAGIC); + (*o_data)->iv_size = revle32(bytes); + (*o_data)->iv_algorithmReserved = revle32(nibbles); + (*o_data)->iv_length = revle32(i_length); + (*o_data)->iv_scanSelect = revle32((uint32_t)(i_scanSelect >> 32)); + (*o_data)->iv_headerVersion = COMPRESSED_SCAN_DATA_VERSION; + (*o_data)->iv_flushOptimization = i_flushOptimization; + (*o_data)->iv_reserved = 0; + (*o_data)->iv_chipletId = i_chipletId; + + *o_size = bytes; + + rc = SCAN_COMPRESSION_OK; + } + + return rc; +} + + +// Decompress an RS4-encoded string into a output string whose length must be +// exactly i_length bits. +// +// Returns a scan compression return code. + +static int +_rs4_decompress(uint8_t* o_string, + const uint8_t* i_string, + const uint32_t i_length) +{ + int rc; + int state; /* 0 : Rotate, 1 : Scan */ + uint32_t i; /* Nibble index in i_string */ + uint32_t j; /* Nibble index in o_string */ + uint32_t k; /* Loop index */ + uint32_t bits; /* Number of output bits decoded so far */ + uint32_t count; /* Count of rotate nibbles */ + uint32_t nibbles; /* Rotate encoding or scan nibbles to process */ + int r; /* Remainder bits */ + + rc = 0; + i = 0; + j = 0; + bits = 0; + state = 0; + + // Decompress the bulk of the string + + do { + if (state == 0) { + nibbles = stop_decode(&count, i_string, i); + if ((bits + (4 * count)) > i_length) { + rc = BUG(SCAN_DECOMPRESSION_SIZE_ERROR); + break; + } + i += nibbles; + bits += (4 * count); + for (k = 0; k < count; k++) { + set_nibble(o_string, j, 0); + j++; + } + state = 1; + } else { + nibbles = get_nibble(i_string, i); + i++; + if (nibbles == 0) { + break; + } + if ((bits + (4 * nibbles)) > i_length) { + rc = BUG(SCAN_DECOMPRESSION_SIZE_ERROR); + break; + } + bits += (4 * nibbles); + for (k = 0; k < nibbles; k++) { + set_nibble(o_string, j, get_nibble(i_string, i)); + i++; + j++; + } + state = 0; + } + } while (1); + + // Now handle string termination + + if (!rc) { + r = get_nibble(i_string, i); + i++; + if (r != 0) { + if ((bits + r) > i_length) { + rc = BUG(SCAN_DECOMPRESSION_SIZE_ERROR); + } else { + bits += r; + set_nibble(o_string, j, get_nibble(i_string, i)); + } + } + } + + // Final check to insure the string was valid + + if (!rc) { + if (bits != i_length) { + rc = BUGX(SCAN_DECOMPRESSION_SIZE_ERROR, + "bits = %zu, i_length = %zu\n", + bits, i_length); + } + } + + return rc; +} + + +int +rs4_decompress(uint8_t** o_string, + uint32_t* o_length, + const CompressedScanData* i_data) +{ + int rc; + uint32_t bytes; + + do { + if (revle32(i_data->iv_magic) != RS4_MAGIC) { + rc = BUG(SCAN_DECOMPRESSION_MAGIC_ERROR); + break; + } + + *o_length = revle32(i_data->iv_length); + bytes = ((*o_length + 7) / 8) * 8; + *o_string = (uint8_t*)calloc(bytes, 1); + if (*o_string == 0) { + rc = BUG(SCAN_COMPRESSION_NO_MEMORY); + break; + } + + rc = _rs4_decompress(*o_string, + (uint8_t*)i_data + sizeof(CompressedScanData), + *o_length); + } while (0); + + return rc; +} + + diff --git a/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_scan_compression.H b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_scan_compression.H new file mode 100644 index 000000000..73585572f --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_scan_compression.H @@ -0,0 +1,271 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/p8_scan_compression.H $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +#ifndef __P8_SCAN_COMPRESSION_H__ +#define __P8_SCAN_COMPRESSION_H__ + +// $Id: p8_scan_compression.H,v 1.1 2012/04/16 23:56:00 bcbrock Exp $ +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/utils/p8_scan_compression.H,v $ +//------------------------------------------------------------------------------ +// *! (C) Copyright International Business Machines Corp. 2011 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//------------------------------------------------------------------------------ +// *! OWNER NAME: Bishop Brock Email: Bishop Brock; bcbrock@us.ibm.com +// *! +// *! General Description: +// *! +// *! See below. +//------------------------------------------------------------------------------ +// +// Note: This file was originally named p8_scan_compression.c; See CVS archive +// for revision history of p8_scan_compression.c. + +/// \file p8_scan_compression.H +/// \brief Structure definitions and protoypes related to scan chain +/// compression. +/// +/// This header declares and documents the entry points defined in +/// p8_scan_compression.C. Some constants are also required by the scan +/// decompression PORE assembly procedures. + +#include "fapi_sbe_common.H" + +#ifndef __ASSEMBLER__ + +#include <stdint.h> + +/// Compressed Scan Chain Data Structure Format +/// +/// The compressed scan ring data structure must be 8-byte aligned in +/// memory. The container data structure consists of this 24-byte header +/// followed by an arbitrary number of 8 byte doublewords containing the +/// compressed scan data. Images are always stored and processed in +/// big-endian byte order. This container format is common across all +/// decompression algorithms. +/// +/// Bytes - Content +/// +/// 0:3 - A 32-bit "magic number" that identifies and validates the +/// compression algorithm and algorithm version used to compress the data. +/// +/// 4:7 - The 32-bit size of the entire data structure in \e bytes. This +/// consists of this 24-byte header plus the compressed scan data. This value +/// is always a multiple of 8. +/// +/// 8:11 - This 32-bit value is reserved to the compression +/// algorithm. Typically this field is used to record the 'size' of the +/// compressed string in units specific to each algorithm. +/// +/// 12:15 - The length of the original scan chain in \e bits. +/// +/// 16:19 - The 32 high-order bits of the value written to the Scan Select +/// register to set up the scan. The Scan Select register only defines these +/// bits. +/// +/// 20 - The Scan Chain Data Structure version number +/// +/// 21 - Flush-optimize : Is this byte is non-zero, the ring state to be +/// modified is the flush state of the ring. +/// +/// 22 - Reserved +/// +/// 23 - The 7-bit pervasive chiplet Id + Multicast bit of the chiplet to +/// scan. This value is loaded directly into P0. The decompression +/// algorithms provide two entry points - one that uses this value as the +/// chiplet Id, and another that allows the caller to specify the chiplet Id +/// in the call. + +typedef struct { + + /// Magic number - See \ref scan_compression_magic + uint32_t iv_magic; + + /// Total size in bytes, including the container header + uint32_t iv_size; + + /// Reserved to the algorithm + uint32_t iv_algorithmReserved; + + /// Length of the original scan chain in bits + uint32_t iv_length; + + /// The high-order 32 bits of the Scan Select Register + /// + /// Note that the Scan Select register only defines the high order 32 + /// bits, so we only need store the 32 high-order bits. This field is + /// 8-byte aligned so that the doubleword loaded by the PORE can be + /// directly written to the scan select register. + uint32_t iv_scanSelect; + + /// Data structure (header) version + uint8_t iv_headerVersion; + + /// Flush-state optimization + /// + /// Normally, modifying the state of the ring requires XOR-ing the + /// difference state (the compressed state) with the current ring state as + /// it will appear in the Scan Data Register. If the current state of the + /// ring is the scan-0 flush state, then by definition the Scan Data + /// Register is always 0. Therefore we can simply write the difference to + /// the Scan Data Register rather than using a read-XOR-write. + uint8_t iv_flushOptimization; + + /// Alignment padding + uint8_t iv_reserved; + + /// 7-bit pervasive chiplet Id + Multicast bit + /// + /// This field is right-justified in an 8-byte aligned doubleword so that + /// the P0 register can be directly updated from the doubelword value in a + /// data register. + uint8_t iv_chipletId; + +} CompressedScanData; + + +/// Endian-translate a CompressedScanData structure +/// +/// \param o_data A pointer to a CompressedScanData structure to receive the +/// endian-translated form of \a i_data. +/// +/// \param i_data A pointer to the original CompressedScanData structure. +/// +/// This API performs an endian-converting copy of a CompressedScanData +/// structure. This copy is guaranteed to be done in such a way that \a i_data +/// and \a o_data may be the same pointer for in-place conversion. Due to the +/// symmetry of reverse, translating a structure twice is always guaranteed to +/// return the origial structure to its original byte order. +void +compressed_scan_data_translate(CompressedScanData* o_data, + CompressedScanData* i_data); + + +/// Compress a scan string using the RS4 compression algorithm +/// +/// \param o_data This algorithm uses malloc() to allocate memory for the +/// compresed data, and returns a pointer to this memory in \a o_data. After +/// the call this memory is owned by the caller who is responsible for +/// free()-ing the data area once it is no longer required. Note that the +/// CompressedScanData is always created in big-endian format, however the +/// caller can use compresed_scan_data_translate() to create a copy of the +/// header in host format. +/// +/// \param o_size The effective size of the entire compressed scan data +/// structure (header + compressed data) pointed to by \a o_data, in bytes. +/// This value will always be a multiple of 8. +/// +/// \param i_string The string to compress. Scan data to compress is +/// left-justified in this input string. +/// +/// \param i_length The length of the input string in \e bits. It is assumed +/// the \a i_string contains at least (\a i_length + 7) / 8 bytes. +/// +/// \param i_scanSelect The 64-bit value written to the Scan Select register +/// to set up for the scan. Only the 32 high-order bits are actually stored. +/// +/// \param i_chipletId The 7-bit value for the iv_chipletId field of the +/// CompressedScanData. +/// +/// \param i_flushOptimization This input parameter should be set to a non-0 +/// value if it is known that this ring difference will be applied to a scan-0 +/// flush state. This will improve the performance of the decompress-scan +/// routine. If the initial state of the ring is unknown, set this parameter +/// to 0. +/// +/// \returns See \ref scan_compression_codes +int +rs4_compress(CompressedScanData** o_data, + uint32_t* o_size, + const uint8_t* i_string, + const uint32_t i_length, + const uint64_t i_scanSelect, + const uint8_t i_chipletId, + const uint8_t i_flushOptimization); + + +/// Decompress a scan string compressed using the RS4 compression algorithm +/// +/// \param o_string The API malloc()-s this data area to contain the +/// decompressed string. After this call the caller owns \a o_string and is +/// responsible for free()-ing this data area once it is no longer required. +/// +/// \param o_length The length of the decompressed string in \e bits. The +/// caller may assume that \a o_string contains at least (\a o_length + 7) / 8 +/// bytes. +/// +/// \param i_data A pointer to the CompressedScanData header + data to be +/// decompressed. +int +rs4_decompress(uint8_t** o_string, + uint32_t* o_length, + const CompressedScanData* i_data); + +#endif // __ASSEMBLER__ + + +/// The current version of the CompressedScanData structure +/// +/// This constant is required to be a #define to guarantee consistency between +/// the header format and cmopiled code. +#define COMPRESSED_SCAN_DATA_VERSION 1 + +/// The size of the CompressedScanData structure +CONST_UINT8_T(COMPRESSED_SCAN_DATA_SIZE, 24); + + +/// \defgroup scan_compression_magic Scan Compression Magic Numbers +/// +/// @ { + +/// RS4 Magic +CONST_UINT32_T(RS4_MAGIC, 0x52533401); /* "RS4" + Version 0x01 */ + +/// @} + + +/// \defgroup scan_compression_codes Scan Compression Return Codes +/// +/// @{ + +/// Normal return code +CONST_UINT8_T(SCAN_COMPRESSION_OK, 0); + +/// The (de)compression algorithm could not allocate enough memory for the +/// (de)compression. +CONST_UINT8_T(SCAN_COMPRESSION_NO_MEMORY, 1); + +/// Magic number mismatch on scan decompression +CONST_UINT8_T(SCAN_DECOMPRESSION_MAGIC_ERROR, 2); + +/// Decompression size error +/// +/// Decompression produced a string of a size different than indicated in the +/// header, indicating either a bug or data corruption. Note that the entire +/// application should be considered corrupted if this error occurs since it +/// may not be discovered until after the decompression buffer is overrun. +CONST_UINT8_T(SCAN_DECOMPRESSION_SIZE_ERROR, 3); + +/// @} + +#endif // __P8_SCAN_COMPRESSION_H__ diff --git a/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/pgas.h b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/pgas.h new file mode 100644 index 000000000..92fb57646 --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/pgas.h @@ -0,0 +1,1044 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/pgas.h $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +#ifndef __PGAS_H__ +#define __PGAS_H__ + +#define __PGAS__ + +// $Id: pgas.h,v 1.16 2012/05/23 19:03:40 bcbrock Exp $ + +// ** WARNING : This file is maintained as part of the OCC firmware. Do ** +// ** not edit this file in the PMX area, the hardware procedure area, ** +// ** or the PoreVe area as any changes will be lost. ** + +/// \file pgas.h +/// \brief Pore GAS +/// +/// PGAS is documented in a seperate standalone document entitled <em> PGAS : +/// PORE GAS (GNU Assembler) User's and Reference Manual <\em>. +/// +/// This file defines support macros for the GNU PORE assembler, and the PORE +/// inline assembler and disassebler which follow the PGAS assembly syntax. +/// If the compile swith PGAS_PPC is defined in the environment then pgas.h +/// includes pgas_ppc.h which transforms a PowerPC assembler into an assembler +/// for PORE. + +// These are the opcodes and mnemonics as defined by the PORE hardware +// manual. Many of them will change names slightly in PGAS. + +#define PORE_OPCODE_NOP 0x0f +#define PORE_OPCODE_WAIT 0x01 +#define PORE_OPCODE_TRAP 0x02 +#define PORE_OPCODE_HOOK 0x4f + +#define PORE_OPCODE_BRA 0x10 +#define PORE_OPCODE_BRAZ 0x12 +#define PORE_OPCODE_BRANZ 0x13 +#define PORE_OPCODE_BRAI 0x51 +#define PORE_OPCODE_BSR 0x14 +#define PORE_OPCODE_BRAD 0x1c +#define PORE_OPCODE_BSRD 0x1d +#define PORE_OPCODE_RET 0x15 +#define PORE_OPCODE_CMPBRA 0x56 +#define PORE_OPCODE_CMPNBRA 0x57 +#define PORE_OPCODE_CMPBSR 0x58 +#define PORE_OPCODE_LOOP 0x1f + +#define PORE_OPCODE_ANDI 0x60 +#define PORE_OPCODE_ORI 0x61 +#define PORE_OPCODE_XORI 0x62 + +#define PORE_OPCODE_AND 0x25 +#define PORE_OPCODE_OR 0x26 +#define PORE_OPCODE_XOR 0x27 + +#define PORE_OPCODE_ADD 0x23 +#define PORE_OPCODE_ADDI 0x24 +#define PORE_OPCODE_SUB 0x29 +#define PORE_OPCODE_SUBI 0x28 +#define PORE_OPCODE_NEG 0x2a + +#define PORE_OPCODE_COPY 0x2c +#define PORE_OPCODE_ROL 0x2e + +#define PORE_OPCODE_LOAD20 0x30 +#define PORE_OPCODE_LOAD64 0x71 +#define PORE_OPCODE_SCR1RD 0x32 +#define PORE_OPCODE_SCR1RDA 0x73 +#define PORE_OPCODE_SCR2RD 0x36 +#define PORE_OPCODE_SCR2RDA 0x77 +#define PORE_OPCODE_WRI 0x78 +#define PORE_OPCODE_BS 0x74 +#define PORE_OPCODE_BC 0x75 +#define PORE_OPCODE_SCR1WR 0x39 +#define PORE_OPCODE_SCR2WR 0x3a +#define PORE_OPCODE_SCAND 0x7c + + +// These are the PGAS versions of the PORE opcodes used in the legacy PGAS_PPC +// assembler and the current PORE inline assembler/disassembler. + +#define PGAS_OPCODE_NOP PORE_OPCODE_NOP +#define PGAS_OPCODE_WAITS PORE_OPCODE_WAIT +#define PGAS_OPCODE_TRAP PORE_OPCODE_TRAP +#define PGAS_OPCODE_HOOKI PORE_OPCODE_HOOK + +#define PGAS_OPCODE_BRA PORE_OPCODE_BRA +#define PGAS_OPCODE_BRAZ PORE_OPCODE_BRAZ +#define PGAS_OPCODE_BRANZ PORE_OPCODE_BRANZ +#define PGAS_OPCODE_BRAI PORE_OPCODE_BRAI +#define PGAS_OPCODE_BSR PORE_OPCODE_BSR +#define PGAS_OPCODE_BRAD PORE_OPCODE_BRAD +#define PGAS_OPCODE_BSRD PORE_OPCODE_BSRD +#define PGAS_OPCODE_RET PORE_OPCODE_RET +#define PGAS_OPCODE_CMPIBRAEQ PORE_OPCODE_CMPBRA +#define PGAS_OPCODE_CMPIBRANE PORE_OPCODE_CMPNBRA +#define PGAS_OPCODE_CMPIBSREQ PORE_OPCODE_CMPBSR +#define PGAS_OPCODE_LOOP PORE_OPCODE_LOOP + +#define PGAS_OPCODE_ANDI PORE_OPCODE_ANDI +#define PGAS_OPCODE_ORI PORE_OPCODE_ORI +#define PGAS_OPCODE_XORI PORE_OPCODE_XORI + +#define PGAS_OPCODE_AND PORE_OPCODE_AND +#define PGAS_OPCODE_OR PORE_OPCODE_OR +#define PGAS_OPCODE_XOR PORE_OPCODE_XOR + +#define PGAS_OPCODE_ADD PORE_OPCODE_ADD +#define PGAS_OPCODE_ADDS PORE_OPCODE_ADDI +#define PGAS_OPCODE_SUB PORE_OPCODE_SUB +#define PGAS_OPCODE_SUBS PORE_OPCODE_SUBI +#define PGAS_OPCODE_NEG PORE_OPCODE_NEG + +#define PGAS_OPCODE_MR PORE_OPCODE_COPY +#define PGAS_OPCODE_ROLS PORE_OPCODE_ROL + +#define PGAS_OPCODE_LS PORE_OPCODE_LOAD20 +#define PGAS_OPCODE_LI PORE_OPCODE_LOAD64 +#define PGAS_OPCODE_LD0 PORE_OPCODE_SCR1RD /* Used by LD */ +#define PGAS_OPCODE_LD0ANDI PORE_OPCODE_SCR1RDA /* Used by LDANDI */ +#define PGAS_OPCODE_LD1 PORE_OPCODE_SCR2RD /* Used by LD */ +#define PGAS_OPCODE_LD1ANDI PORE_OPCODE_SCR2RDA /* Used by LDANDI */ +#define PGAS_OPCODE_STI PORE_OPCODE_WRI +#define PGAS_OPCODE_BSI PORE_OPCODE_BS +#define PGAS_OPCODE_BCI PORE_OPCODE_BC +#define PGAS_OPCODE_STD0 PORE_OPCODE_SCR1WR /* Used by STD */ +#define PGAS_OPCODE_STD1 PORE_OPCODE_SCR2WR /* Used by STD */ +#define PGAS_OPCODE_SCAND PORE_OPCODE_SCAND + + +// These are the programmer-visible register names as defined by the PORE +// hardware manual. All of these names (except the PC) appear differently in +// the PGAS syntax, in some cases to reduce confusion, in other cases just to +// have more traditional short mnemonics. + +#define PORE_REGISTER_PRV_BASE_ADDR0 0x0 +#define PORE_REGISTER_PRV_BASE_ADDR1 0x1 +#define PORE_REGISTER_OCI_BASE_ADDR0 0x2 +#define PORE_REGISTER_OCI_BASE_ADDR1 0x3 +#define PORE_REGISTER_SCRATCH0 0x4 +#define PORE_REGISTER_SCRATCH1 0x5 +#define PORE_REGISTER_SCRATCH2 0x6 +#define PORE_REGISTER_ERROR_MASK 0x7 +#define PORE_REGISTER_EXE_TRIGGER 0x9 +#define PORE_REGISTER_DATA0 0xa +#define PORE_REGISTER_PC 0xe +#define PORE_REGISTER_IBUF_ID 0xf + + +// PgP IBUF_ID values + +#define PORE_ID_GPE0 0x00 +#define PORE_ID_GPE1 0x01 +#define PORE_ID_SLW 0x08 +#define PORE_ID_SBE 0x04 + + +// Condition Codes + +#define PORE_CC_UGT 0x8000 +#define PORE_CC_ULT 0x4000 +#define PORE_CC_SGT 0x2000 +#define PORE_CC_SLT 0x1000 +#define PORE_CC_C 0x0800 +#define PORE_CC_V 0x0400 +#define PORE_CC_N 0x0200 +#define PORE_CC_Z 0x0100 + + +#ifdef __ASSEMBLER__ + +//////////////////////////////////////////////////////////////////////////// +// PGAS Base Assembler Support +//////////////////////////////////////////////////////////////////////////// + + + ////////////////////////////////////////////////////////////////////// + // Condition Codes + ////////////////////////////////////////////////////////////////////// + + .set CC_UGT, PORE_CC_UGT + .set CC_ULT, PORE_CC_ULT + .set CC_SGT, PORE_CC_SGT + .set CC_SLT, PORE_CC_SLT + .set CC_C, PORE_CC_C + .set CC_V, PORE_CC_V + .set CC_N, PORE_CC_N + .set CC_Z, PORE_CC_Z + + + ////////////////////////////////////////////////////////////////////// + // Utility Macros + ////////////////////////////////////////////////////////////////////// + + // 'Undefine' PowerPC mnemonics to trap programming errors + + .macro ..undefppc1, i + .ifnc \i, ignore + .macro \i, args:vararg + .error "This is a PowerPC opcode - NOT a PGAS opcode or extended mnemonic" + .endm + .endif + .endm + + .macro .undefppc, i0, i1=ignore, i2=ignore, i3=ignore + ..undefppc1 \i0 + ..undefppc1 \i1 + ..undefppc1 \i2 + ..undefppc1 \i3 + .endm + + + ////////////////////////////////////////////////////////////////////// + // Argument Checking Macros + ////////////////////////////////////////////////////////////////////// + // + // These macros remain in the final pgas.h file because 1) they are + // required for some PGAS pseudo-ops, and 2) to support robust + // assembler macro definitions. + + // Check an unsigned immediate for size + + .macro ..checku, x:req, bits:req, err="Unsigned value too large" + + .if (((\bits) <= 0) || ((\bits) > 63)) + .error "The number of bits must be in the range 0 < bits < 64" + .endif + + .iflt (\x) + .error "An unsigned value is required here" + .endif + + .ifgt ((\x) - (0xffffffffffffffff >> (64 - (\bits)))) + .error "\err" + .endif + + .endm + + // Check unsigned 16/22-bit immediates for size + // + // In general, PGAS can check immediate values for size restrictions, + // but unfortunately is not able to check address offset immediates for + // range. + + .macro ..check_u16, u16 + ..checku (\u16), 16, "Unsigned immediate is larger than 16 bits" + .endm + + .macro ..check_u24, u24 + ..checku (\u24), 24, "Unsigned immediate is larger than 24 bits" + .endm + + // Check a 16/20/22-bit signed immediate for size + + .macro ..check_s16, s16 + .iflt \s16 + .iflt \s16 + 0x8000 + .error "Immediate value too small for a signed 16-bit field" + .endif + .else + .ifgt \s16 - 0x7fff + .error "Immediate value too large for a signed 16-bit field" + .endif + .endif + .endm + + .macro ..check_s20, s20 + .iflt \s20 + .iflt \s20 + 0x80000 + .error "Immediate value too small for a signed 20-bit field" + .endif + .else + .ifgt \s20 - 0x7ffff + .error "Immediate value too large for a signed 20-bit field" + .endif + .endif + .endm + + .macro ..check_s22, s22 + .iflt \s22 + .iflt \s22 + 0x200000 + .error "Immediate value too small for a signed 22-bit field" + .endif + .else + .ifgt \s22 - 0x1fffff + .error "Immediate value too large for a signed 22-bit field" + .endif + .endif + .endm + + // Check a putative SCOM address for bits 0 and 8:11 == 0. + + .macro ..check_scom, address + .if ((\address) & 0x80f00000) + .error "Valid SCOM addresses must have bits 0 and 8:11 equal to 0." + .endif + .endm + + // A register required to be D0 + + .macro ..d0, reg + .if (\reg != D0) + .error "Data register D0 is required here" + .endif + .endm + + // A register pair required to be D0, D1 in order + + .macro ..d0d1, reg1, reg2 + .if (((\reg1) != D0) && ((\reg2) != D1)) + .error "Register-Register ALU operations are only defined on the source pair D0, D1" + .endif + .endm + + // A register pair required to be D0, D1 in any order + .macro ..dxdy, reg1, reg2, err="Expecting D0, D1 in either order" + .if !((((\reg1) == D0) && ((\reg2) == D1)) || \ + (((\reg1) == D1) && ((\reg2) == D0))) + .error "\err" + .endif + .endm + + // A register pair required to be the same register + + .macro ..same, dest, src + .if ((\dest) != (\src)) + .error "PGAS requires the src and dest register of ADDS/SUBS to be explicit and identical" + .endif + .endm + + // A "Data" register + + .macro ..data, reg:req, err="Expecting a 'Data' register" + .if (\reg != D0) + .if (\reg != D1) + .error "\err" + .endif + .endif + .endm + + // An "Address" register + + .macro ..address, reg:req, err=:"Expecting an 'Address' register" + .if (\reg != A0) + .if (\reg != A1) + .error "\err" + .endif + .endif + .endm + + // A "Pervasive Chiplet ID" register + + .macro ..pervasive_chiplet_id, reg:req, err="Expecting a 'Pervasive Chiplet ID' register" + .if (\reg != P0) + .if (\reg != P1) + .error "\err" + .endif + .endif + .endm + + // A "Branch Compare Data" register + + .macro ..branch_compare_data, reg + .if (\reg != D0) + .if (\reg != D1) + .if (\reg != CTR) + .error "Expecting a 'Branch Compare Data' register" + .endif + .endif + .endif + .endm + + // An "LS Destination" register; Also the set for ADDS/SUBS + + .macro ..ls_destination, reg + .if (\reg != D0) + .if (\reg != D1) + .if (\reg != A0) + .if (\reg != A1) + .if (\reg != P0) + .if (\reg != P1) + .if (\reg != CTR) + .error "Expecting an 'LS Destination' register" + .endif + .endif + .endif + .endif + .endif + .endif + .endif + .endm + + // An "LI Destination" register + + .macro ..li_destination, reg + .if (\reg != D0) + .if (\reg != D1) + .if (\reg != A0) + .if (\reg != A1) + .if (\reg != CTR) + .error "Expecting an 'LI Destination' register" + .endif + .endif + .endif + .endif + .endif + .endm + + // An "LIA Destination" register + + .macro ..lia_destination, reg + .if (\reg != D0) + .if (\reg != D1) + .if (\reg != A0) + .if (\reg != A1) + .if (\reg != TBAR) + .error "Expecting an 'LIA Destination' register" + .endif + .endif + .endif + .endif + .endif + .endm + + // An "MR Source" register + + .macro ..mr_source, reg + .if (\reg != D0) + .if (\reg != D1) + .if (\reg != A0) + .if (\reg != A1) + .if (\reg != P0) + .if (\reg != P1) + .if (\reg != CTR) + .if (\reg != PC) + .if (\reg != ETR) + .if (\reg != SPRG0) + .if (\reg != IFR) + .if (\reg != EMR) + .error "Expecting an 'MR Source' register" + .endif + .endif + .endif + .endif + .endif + .endif + .endif + .endif + .endif + .endif + .endif + .endif + .endm + + // An "MR Destination" register + + .macro ..mr_destination, reg + .if (\reg != D0) + .if (\reg != D1) + .if (\reg != A0) + .if (\reg != A1) + .if (\reg != P0) + .if (\reg != P1) + .if (\reg != CTR) + .if (\reg != PC) + .if (\reg != ETR) + .if (\reg != SPRG0) + .if (\reg != EMR) + .error "Expecting an 'MR Destination' register" + .endif + .endif + .endif + .endif + .endif + .endif + .endif + .endif + .endif + .endif + .endif + .endm + + + ////////////////////////////////////////////////////////////////////// + // PORE address spaces + ////////////////////////////////////////////////////////////////////// + + // The ..set_address_space pseudo-op defines the default address + // space. It must be defined in order to use BRAA, BRAIA, BSR and + // CMPIBSR. Pseudo-ops are provided to set the default space of the + // program. Note that code assembled for PNOR will also work in the + // OCI space in the Sleep/Winkle engine. + + .set PORE_SPACE_UNDEFINED, 0xffff + .set PORE_SPACE_OCI, 0x8000 + .set PORE_SPACE_PNOR, 0x800b + .set PORE_SPACE_OTPROM, 0x0001 + .set PORE_SPACE_SEEPROM, 0x800c + .set PORE_SPACE_PIBMEM, 0x0008 + + .macro ..set_default_space, s + ..check_u16 (\s) + .set _PGAS_DEFAULT_SPACE, (\s) + .endm + + .macro ..check_default_space + .if (_PGAS_DEFAULT_SPACE == PORE_SPACE_UNDEFINED) + .error "The PGAS default address space has not been defined" + .endif + .endm + + ..set_default_space PORE_SPACE_UNDEFINED + + .macro .oci + ..set_default_space PORE_SPACE_OCI + .endm + + .macro .pnor + ..set_default_space PORE_SPACE_PNOR + .endm + + .macro .seeprom + ..set_default_space PORE_SPACE_SEEPROM + .endm + + .macro .otprom + ..set_default_space PORE_SPACE_OTPROM + .endm + + .macro .pibmem + ..set_default_space PORE_SPACE_PIBMEM + .pibmem_port (PORE_SPACE_PIBMEM & 0xf) + .endm + + + ////////////////////////////////////////////////////////////////////// + // Address-Generation Pseudo Ops + ////////////////////////////////////////////////////////////////////// + + // .QUADA, .QUADIA + + .macro .quada, offset:req + ..check_default_space + .long _PGAS_DEFAULT_SPACE + .long (\offset) + .endm + + .macro .quadia, space:req, offset:req + ..check_u16 (\space) + .long (\space) + .long (\offset) + .endm + + ////////////////////////////////////////////////////////////////////// + // "A"- and "IA"-form Instructions + ////////////////////////////////////////////////////////////////////// + + // BRAA (Branch Address) is a 'long branch' to an address in the + // default memory space. + + .macro braa, offset:req + braia _PGAS_DEFAULT_SPACE, (\offset) + .endm + + // LA (Load Address) loads the full address of an address in the + // default memory space. + + .macro la, dest:req, offset:req + lia (\dest), _PGAS_DEFAULT_SPACE, (\offset) + .endm + + // STA (Store Address) stores the full address of an address in the + // default memory space. + + .macro sta, mem_offset:req, base:req, addr_offset:req + stia (\mem_offset), (\base), _PGAS_DEFAULT_SPACE, (\addr_offset) + .endm + + // BSRIA is a subroutine branch into another memory space. This has to + // be emulated by a local subroutine branch and a BRAIA. + + .macro bsria, space:req, offset:req + bsr 27742f + bra 27743f +27742: + braia (\space), (\offset) +27743: + .endm + + +//////////////////////////////////////////////////////////////////////////// +// Extended Mnemonics, Macros and Special Cases +//////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////// + // TFB<c> - Test flags and branch conditionally + //////////////////////////////////////////////////////////////////////' + + .macro ..tfb, dest, target, flags + ..data (\dest) + mr (\dest), IFR + andi (\dest), (\dest), (\flags) + branz (\dest), (\target) + .endm + + .macro ..tfbn dest, target, flags + ..data (\dest) + mr (\dest), IFR + andi (\dest), (\dest), (\flags) + braz (\dest), (\target) + .endm + + .macro tfbcs, dest:req, target:req + ..tfb (\dest), (\target), CC_C + .endm + + .macro tfbcc, dest:req, target:req + ..tfbn (\dest), (\target), CC_C + .endm + + .macro tfbvs, dest:req, target:req + ..tfb (\dest), (\target), CC_V + .endm + + .macro tfbvc, dest:req, target:req + ..tfbn (\dest), (\target), CC_V + .endm + + .macro tfbns, dest:req, target:req + ..tfb (\dest), (\target), CC_N + .endm + + .macro tfbnc, dest:req, target:req + ..tfbn (\dest), (\target), CC_N + .endm + + .macro tfbeq, dest:req, target:req + ..tfb (\dest), (\target), CC_Z + .endm + + .macro tfbne, dest:req, target:req + ..tfbn (\dest), (\target), CC_Z + .endm + + .macro tfbult, dest:req, target:req + ..tfb (\dest), (\target), CC_ULT + .endm + + .macro tfbule, dest:req, target:req + ..tfbn (\dest), (\target), CC_UGT + .endm + + .macro tfbuge, dest:req, target:req + ..tfbn (\dest), (\target), CC_ULT + .endm + + .macro tfbugt, dest:req, target:req + ..tfb (\dest), (\target), CC_UGT + .endm + + .macro tfbslt, dest:req, target:req + ..tfb (\dest), (\target), CC_SLT + .endm + + .macro tfbsle, dest:req, target:req + ..tfbn (\dest), (\target), CC_SGT + .endm + + .macro tfbsge, dest:req, target:req + ..tfbn (\dest), (\target), CC_SLT + .endm + + .macro tfbsgt, dest:req, target:req + ..tfb (\dest), (\target), CC_SGT + .endm + + + ////////////////////////////////////////////////////////////////////// + // TEB<eng> - Test Engine and branch if engine. + ////////////////////////////////////////////////////////////////////// + // + // All but GPE0 use a 1-hot code. + + .macro tebgpe0, dest:req, target:req + mr (\dest), IFR + andi (\dest), (\dest), 0xf + braz (\dest), (\target) + .endm + + .macro tebgpe1, dest:req, target:req + mr (\dest), IFR + andi (\dest), (\dest), PORE_ID_GPE1 + branz (\dest), (\target) + .endm + + .macro tebslw, dest:req, target:req + mr (\dest), IFR + andi (\dest), (\dest), PORE_ID_SLW + branz (\dest), (\target) + .endm + + .macro tebsbe, dest:req, target:req + mr (\dest), IFR + andi (\dest), (\dest), PORE_ID_SBE + branz (\dest), (\target) + .endm + + + ////////////////////////////////////////////////////////////////////// + // LPCS - Load Pervasive Chiplet from Scom address + ////////////////////////////////////////////////////////////////////// + + .macro lpcs, dest:req, scom:req + ..pervasive_chiplet_id (\dest) + ..check_scom (\scom) + ls (\dest), (((\scom) >> 24) & 0x7f) + .endm + + + ////////////////////////////////////////////////////////////////////// + // Shift/Mask extended mnemonics + ////////////////////////////////////////////////////////////////////// + + // All of the 'dot-dot' macros assume that error and identity + // checking has been done on the arguments already. + + // The initial register-register rotate. If the incoming shift amount + // is 0 then the instruction generated is a simple MR. + + .macro ..rotlrr, ra, rs, sh + + .if (\sh) >= 32 + rols (\ra), (\rs), 32 + ..rotlr (\ra), ((\sh) - 32) + .elseif (\sh) >= 16 + rols (\ra), (\rs), 16 + ..rotlr (\ra), ((\sh) - 16) + .elseif (\sh) >= 8 + rols (\ra), (\rs), 8 + ..rotlr (\ra), ((\sh) - 8) + .elseif (\sh) >= 4 + rols (\ra), (\rs), 4 + ..rotlr (\ra), ((\sh) - 4) + .elseif (\sh) >= 1 + rols (\ra), (\rs), 1 + ..rotlr (\ra), ((\sh) - 1) + .else + mr (\ra), (\rs) + .endif + + .endm + + + // Subsequent rotation of the same register. The SH should never be 0 + // here. + + .macro ..rotlr, ra, sh + + .if (\sh) >= 32 + rols (\ra), (\ra), 32 + ..rotlr (\ra), ((\sh) - 32) + .elseif (\sh) >= 16 + rols (\ra), (\ra), 16 + ..rotlr (\ra), ((\sh) - 16) + .elseif (\sh) >= 8 + rols (\ra), (\ra), 8 + ..rotlr (\ra), ((\sh) - 8) + .elseif (\sh) >= 4 + rols (\ra), (\ra), 4 + ..rotlr (\ra), ((\sh) - 4) + .elseif (\sh) >= 1 + rols (\ra), (\ra), 1 + ..rotlr (\ra), ((\sh) - 1) + + .endif + + .endm + + + // RLDINM RA, RS, SH, MB, ME + // + // Defined as if there were an equivalent PowerPC instruction. The + // 'word' forms of the PowerPC instructions and extended mnemonics are + // undefined in order to catch programming typos. + + .undefppc rlwinm, extrwi, rotlwi, rotrwi + .undefppc slwi, srwi + + .macro rldinm, ra:req, rs:req, sh:req, mb:req, me:req + + .if ((\sh) < 0) || ((\sh) > 63) + .error "SH must be in the range 0..63" + .endif + .if ((\mb) < 0) || ((\mb) > 63) + .error "MB must be in the range 0..63" + .endif + .if ((\me) < 0) || ((\me) > 63) + .error "ME must be in the range 0..63" + .endif + + .if (((\mb) == 0) && ((\me) == 63) || ((\me) == ((\mb) - 1))) + + // The mask is effectively 0..63, i.e., no mask. This is a + // simple rotate. + + ..rotlrr (\ra), (\rs), (\sh) + + .else + + // We need a mask step. However if SH == 0 and RA == RS we can + // bypass the rotate step. + + .if ((\sh) != 0) || ((\ra) != (\rs)) + ..rotlrr (\ra), (\rs), (\sh) + .endif + .if ((\mb) <= (\me)) + + // This is a straightforward masking operation with a + // single mask. + + andi (\ra), (\ra), ((0xffffffffffffffff >> (\mb)) & (0xffffffffffffffff << (63 - (\me)))) + .else + + // This is a wrapped mask. + // It is created as 2 masks OR-ed together - 0-ME and MB-63 + + andi (\ra), (\ra), (((0xffffffffffffffff >> 0) & (0xffffffffffffffff << (63 - (\me)))) | ((0xffffffffffffffff >> (\mb)) & (0xffffffffffffffff << (63 - 63)))) + .endif + + .endif + + .endm + + // RLDINM Extended Mnemonics + // + // Defined as if they were equivalent to PowerPC 32-bit extended + // mnemonics + + .macro extldi, ra:req, rs:req, n:req, b:req + .if ((\n) < 0) + .error "EXTLDI requires N > 0" + .endif + rldinm (\ra), (\rs), (\b), 0, ((\n) - 1) + .endm + + .macro extrdi, ra:req, rs:req, n:req, b:req + .if ((\n) < 0) + .error "EXTRDI requires N > 0" + .endif + rldinm (\ra), (\rs), (((\b) + (\n)) % 64), (64 - (\n)), 63 + .endm + + .macro rotldi, ra:req, rs:req, n:req + rldinm (\ra), (\rs), (\n), 0, 63 + .endm + + + .macro rotrdi, ra:req, rs:req, n:req + rldinm (\ra), (\rs), (64 - (\n)), 0, 63 + .endm + + + .macro sldi, ra:req, rs:req, n:req + rldinm (\ra), (\rs), (\n), 0, (63 - (\n)) + .endm + + + .macro srdi, ra:req, rs:req, n:req + rldinm (\ra), (\rs), (64 - (\n)), (\n), 63 + .endm + + + // RLDIMI RA, RS, SH, MB, ME + // + // Defined as if there were an equivalent PowerPC instruction. The + // 'word' forms of the PowerPC instructions and extended mnemonics are + // undefined in order to catch programming typos. + // + // Note that unlike the PowerPC instructions, here RLDIMI must destroy + // RS by masking and shifting it, and RA and RS may not be the same + // register. + + .undefppc rlwimi, inslwi, insrwi + + .macro rldimi, ra:req, rs:req, sh:req, mb:req, me:req + + ..dxdy (\ra), (\rs) + + // SH error checks are done by rldinm + + .if (((\mb) == 0) && ((\me) == 63) || ((\me) == ((\mb) - 1))) + + // The mask is effectively 0..63, i.e., no mask. This is a + // simple rotate of RS into RA + + rotldi (\ra), (\rs), (\sh) + + .else + + // Rotate RS and AND with mask + + rldinm (\rs), (\rs), (\sh), (\mb), (\me) + + // Mask out the significant bits of RS, clear that section of + // RA, and logical OR RS into RA + + .if ((\mb) <= (\me)) + + // This is a straightforward masking operation with a + // single mask. + + andi (\ra), (\ra), \ + (~((0xffffffffffffffff >> (\mb)) & (0xffffffffffffffff << (63 - (\me))))) + .else + + // This is a wrapped mask. + // It is created as 2 masks OR-ed together - 0-ME and MB-63 + + andi (\ra), (\ra), \ + (~(((0xffffffffffffffff >> 0) & (0xffffffffffffffff << (63 - (\me)))) | \ + ((0xffffffffffffffff >> (\mb)) & (0xffffffffffffffff << (63 - 63))))) + .endif + + or (\ra), D0, D1 + + .endif + + .endm + + // RLDIMI Extended Mnemonics + // + // Defined as if they were equivalent to PowerPC 32-bit extended + // mnemonics + + .macro insldi, ra:req, rs:req, n:req, b:req + .if ((\n) < 0) + .error "INSLDI requires N > 0" + .endif + rldimi (\ra), (\rs), (64 - (\b)), (\b), ((\b) + (\n) - 1) + .endm + + .macro insrdi, ra:req, rs:req, n:req, b:req + .if ((\n) < 0) + .error "INSRDI requires N > 0" + .endif + rldimi (\ra), (\rs), (64 - (\b) - (\n)), (\b), ((\b) + (\n) - 1) + .endm + + + ////////////////////////////////////////////////////////////////////// + // .HOOK + ////////////////////////////////////////////////////////////////////// + + // The PoreVe (PORE Virtual Environment) is a PORE simulation + // environment that allows the programmer to embed C/C++ code into the + // PORE assembler source code, and arranges for the C/C++ code to be + // executed in-line with the PORE assembly code. Instances of the + // .hook macro are inserted into the assembler input by the + // hook_extractor script, to mark the locations where hooks are + // present. The hook reference is a string that combines the source + // file name with an index number to uniquely identify the hook. + // + // .hook <file name>_<sequence number> + // + // The .hook macro marks the location of each hook in the relocatable + // binaries with special symbols. The symbol name includes the hook + // reference, which is used to locate the hook in the HookManager + // symbol table. Because hooks can be defined in macros, a hook that + // appears once in a source file may appear multiple times in the + // final binary. For this reason each hook must also be tagged with a + // unique index number to avoid symbol name collisions. The + // complexity of the .hook macro is due to the necessity to decode a + // dynamic symbol value (_PGAS_HOOK_INDEX) into its binary string form + // to create the unique symbol name. The final hook symbol has the + // form: + // + // __hook__<unique>_<reference> + // + // where <unique> is a binary string. It is then straightforward to + // locate these symbols in the 'nm' output of the final link and + // create a map of final addresses to the hook routine to call (the + // <reference>) before executing the instruction at that address. + // + // Note: The maximum nesting depth of the recursive ..hook_helper + // macro is log2(index), and the assembler supports nesting of at + // least 32 which is much more than sufficient. + + .set _PGAS_HOOK_INDEX, 0 + + .macro .hook, reference:req + .set _PGAS_HOOK_INDEX, (_PGAS_HOOK_INDEX + 1) + ..hook_helper _PGAS_HOOK_INDEX, "", \reference + .endm + + .macro ..hook_helper, index, unique, reference + .ifeq \index + __hook__\unique\()_\reference\(): + .elseif (\index % 2) + ..hook_helper (\index / 2), 1\unique, \reference + .else + ..hook_helper (\index / 2), 0\unique, \reference + .endif + .endm + + +//////////////////////////////////////////////////////////////////////////// +// Help for Conversion from Old to New PGAS syntax +//////////////////////////////////////////////////////////////////////////// + + .macro loadp, arg:vararg + .error "PGAS now implements 'lpcs' rather then 'loadp'" + .endm + + .macro loadx, arg:vararg + .error "PGAS now implements 'la' rather than 'loadx'" + .endm + +#endif // __ASSEMBLER__ + +#ifdef PGAS_PPC +#include "pgas_ppc.h" +#endif + +#endif // __PGAS_H__ diff --git a/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/pore_bitmanip.H b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/pore_bitmanip.H new file mode 100644 index 000000000..b9ba60424 --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/pore_bitmanip.H @@ -0,0 +1,526 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/pore_bitmanip.H $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +#ifndef __PORE_BITMANIP_H +#define __PORE_BITMANIP_H + +/// \file pore_bitmanip.H +/// \brief Standard bit-manipulation macros (C and Assembler) for PORE code + +#ifdef __ASSEMBLER__ +#include "pgas.h" +#endif + +#include "fapi_sbe_common.H" + +/// \defgroup be64_bits Bit manipulation for 64-bit Big-Endian values +/// +/// \note These macros only work in the assembler context because we build our +/// assemblers to do 64-bit arithmetic, which is required for PORE assembly. +/// +/// @{ + +/// Create a multi-bit mask of \a n bits starting at bit \a b +#define BITS(b, n) ((ULL(0xffffffffffffffff) << (64 - (n))) >> (b)) + +/// Create a single bit mask at bit \a b +#define BIT(b) BITS((b), 1) + +#ifdef __ASSEMBLER__ + +/// Check b, n for legality + + .macro ..checkbits, b:req, n=1 + .if (((\b) < 0) || ((\b) > 63)) + .error "Illegal bit number, must be 0,...,63" + .endif + .if (((\n) < 1) || ((\n) > 64)) + .error "Illegal number of bits, must be 1,...,64" + .endif + .if (((\b) + (\n)) > 64) + .error "Illegal (b + n), must be <= 64" + .endif + .endm + + +/// Set a single bit in a data register +/// +/// \param[in,out] data A Data register (D0/D1), modified by setting bit \a b +/// to 1. +/// +/// \param[in] b The bit position (64-bit, big-endian) to set + + .macro setbit, data:req, b:req + ..checkbits (\b) + ori (\data), (\data), BIT(\b) + .endm + + +/// Set multiple contiguous bits in a data register +/// +/// \param[in,out] data A Data register (D0/D1), modified by setting \a n bits +/// starting at bit \a b to 1. +/// +/// \param[in] b The bit position (64-bit, big-endian) to begin +/// +/// \param[in] n The number of contiguous bits to set + + .macro setbits, data:req, b:req, n:req + ..checkbits (\b), (\n) + ori (\data), (\data), BITS((\b), (\n)) + .endm + + +/// Read-modify-write a SCOM register by setting a bit +/// +/// \param[in,out] data A Data register (D0/D1), first loaded with the value +/// of the SCOM register, then modified by setting bit \a b to 1. The final +/// value of \a data is then stored back to the SCOM register. +/// +/// \param[in] address A 32-bit SCOM address +/// +/// \param[in] prv A pervasive base register (P0/P1) which contains the +/// chiplet ID + multicast bit to use with \a address +/// +/// \param[in] b The bit position (64-bit, big-endian) to set + + .macro setbitscom data:req, address:req, prv:req, b:req + ..checkbits (\b) + .if ((\data) == D0) + bsi D0, (\address), (\prv), BIT(\b) + .else + ld (\data), (\address), (\prv) + setbit (\data), (\b) + std (\data), (\address), (\prv) + .endif + .endm + + +/// Read-modify-write a SCOM register by setting a range of contiguous bits +/// +/// \param[in,out] data A Data register (D0/D1), first loaded with the value +/// of the SCOM register, then modified by setting \a n bits starting at bit +/// \a b to 1. The final value of \a data is then stored back to the SCOM +/// register. +/// +/// \param[in] address A 32-bit SCOM address +/// +/// \param[in] prv A pervasive base register (P0/P1) which contains the +/// chiplet ID + multicast bit to use with \a address +/// +/// \param[in] b The bit position (64-bit, big-endian) to set +/// +/// \param[in] n The number of contiguous bits to set + + .macro setbitsscom data:req, address:req, prv:req, b:req, n:req + ..checkbits (\b), (\n) + .if ((\data) == D0) + bsi D0, (\address), (\prv), BITS((\b),(\n)) + .else + ld (\data), (\address), (\prv) + setbits (\data), (\b), (\n) + std (\data), (\address), (\prv) + .endif + .endm + +/// Set any number of individual bits in a data register +/// +/// \param[in] data The Data register (D0/D1) to modify +/// +/// \param[in] ...bits 1 or more bit positions (64-bit, big-endian) to set +/// +/// For example: +/// +/// - setbitmult D0, 1, 3, 13 +/// +/// sets bits 1, 3 and 13 of D0. + + .macro setbitmult, data:req, bits:vararg + ..setbitmult 0, (\data), \bits + .endm + + // The best I can come up with to implement this macro currently is to + // use a special symbol to accumulate the bit masks. I don't know of a + // way to do this recursively. + + .macro ..accumulate_bitmask, symbol:req, bits:vararg + .ifb \bits + .error "At least 1 bit position must be specified" + .endif + .set \symbol, 0 + .irp b, \bits + .if (((\b) < 0) || ((\b) > 63)) + .error "Illegal bit position, must be 0 <= b < 63" + .endif + .set \symbol, (BIT(\b) | \symbol) + .endr + .endm + + .macro ..setbitmult, invert:req, data:req, bits:vararg + ..accumulate_bitmask __SETBITMULT__, \bits + .if (\invert) + andi (\data), (\data), ~__SETBITMULT__ + .else + ori (\data), (\data), __SETBITMULT__ + .endif + .endm + + +/// Read-modify-write a SCOM register by setting any number of individual bits +/// +/// \param[in,out] data A Data register (D0/D1), first loaded with the value +/// of the SCOM register, then modified by setting any number (> 0) of +/// individual bits. +/// +/// \param[in] address A 32-bit SCOM address +/// +/// \param[in] prv A pervasive base register (P0/P1) which contains the +/// chiplet ID + multicast bit to use with \a address +/// +/// \param[in] ...bits 1 or more bit positions (64-bit, big-endian) to set +/// +/// For example: +/// +/// - setbitmultscom D0, OCC_CONTROL_0x0006B000, P0, 1, 3, 13 +/// +/// sets bits 1, 3 and 13 of OCC_CONTROL. + + .macro setbitmultscom, data:req, address:req, prv:req, bits:vararg + ..setbitmultscom 0, (\data), (\address), (\prv), \bits + .endm + + .macro ..setbitmultscom, \ + invert:req, data:req, address:req, prv:req, bits:vararg + ..accumulate_bitmask __SETBITMULTSCOM__, \bits + .if ((\data) == D0) + + .if (\invert) + bci D0, (\address), (\prv), __SETBITMULTSCOM__ + .else + bsi D0, (\address), (\prv), __SETBITMULTSCOM__ + .endif + + .else + + .if (\invert) + ldandi (\data), (\address), (\prv), ~__SETBITMULTSCOM__ + .else + ld (\data), (\address), (\prv) + ori (\data), (\data), __SETBITMULTSCOM__ + .endif + std (\data), (\address), (\prv) + + .endif + .endm + + +/// Clear a single bit in a data register +/// +/// This macro is the bit-clearing analogue of the \c setbit macro + + .macro clrbit, data:req, b:req + ..checkbits (\b) + andi (\data), (\data), ~BIT(\b) + .endm + + +/// Clear multiple contiguous bits in a data register +/// +/// This macro is the bit-clearing analogue of the \c setbits macro + + + .macro clrbits, data:req, b:req, n:req + ..checkbits (\b), (\n) + andi (\data), (\data), ~BITS((\b), (\n)) + .endm + + +/// Read-modify-write a SCOM register by clearing a bit +/// +/// This macro is the bit-clearing analogue of the \c setbitscom macro + + .macro clrbitscom data:req, address:req, prv:req, b:req + ..checkbits (\b) + .if ((\data) == D0) + bci D0, (\address), (\prv), BIT(\b) + .else + ld (\data), (\address), (\prv) + clrbit (\data), (\b) + std (\data), (\address), (\prv) + .endif + .endm + + +/// Read-modify-write a SCOM register by clearing a range of contiguous bits +/// +/// This macro is the bit-clearing analogue of the \c setbitsscom macro + + .macro clrbitsscom, data:req, address:req, prv:req, b:req, n:req + ..checkbits (\b), (\n) + .if ((\data) == D0) + bci D0, (\address), (\prv), BITS((\b), (\n)) + .else + ld (\data), (\address), (\prv) + clrbits (\data), (\b), (\n) + std (\data), (\address), (\prv) + .endif + .endm + + +/// Clear any number of individual bits in a data register +/// +/// This macro is the bit-clearing analogue of the \c setbitmult macro + + .macro clrbitmult, data:req, bits:vararg + ..setbitmult 1, (\data), \bits + .endm + + +/// Read-modify-write a SCOM register by clearing any number of individual bits +/// +/// This macro is the bit-clearing analogue of the \c setbitmultscom macro + + .macro clrbitmultscom, data:req, address:req, prv:req, bits:vararg + ..setbitmultscom 1, (\data), (\address), (\prv), \bits + .endm + + +/// Extract and right-justify an unsigned bit field +/// +/// \param[out] dest The destination Data register (D0/D1) to receive the +/// right-justified unsigned bit field. +/// +/// \param[in] src The source Data register (D0/D1) that contains the unsigned +/// bit field to extract. +/// +/// \param[in] b The bit positon (64-bit, big-endian) where the bit field +/// begins. +/// +/// \param[in] n The number of contiguous bits beginning at bit \a b to +/// extract. +/// +/// The execution of this macro computes: +/// +/// - dest[64-n:63] <- src[b:b+n-1] +/// - dest[0:64-n] <- 0 +/// +/// Note that the \a dest and \a src registers may be the same Data register. + + .macro extractbits, dest:req, src:req, b:req, n:req + ..checkbits (\b), (\n) + extrdi (\dest), (\src), (\n), (\b) + .endm + + +/// Destructively insert a right-justified immediate value into a bit field +/// +/// \param[out] dest The destination Data register (D0/D1) to be modified. +/// +/// \param[in] b The bit positon (64-bit, big-endian) where the bit field +/// begins. +/// +/// \param[in] n The number of contiguous bits beginning at bit \a b to +/// modify +/// +/// The execution of this macro computes: +/// +/// - dest <- (dest & ~BITS(b, n)) | ((imm & BITS(64 - n, n)) << (64 - n - b)) + + .macro insertbits, dest:req, b:req, n:req, imm:req + ..checkbits (\b), (\n) + andi (\dest), (\dest), ~BITS((\b), (\n)) + ori (\dest), (\dest), \ + (((\imm) & BITS(64 - (\n), (\n))) << ((64 - (\n) - (\b)))) + .endm + + +/// Poll for a bit to be set in a SCOM register with timeout +/// +/// \param[in] dest A Data register (D0/D1) to use for the polling +/// +/// \param[in] address A 32-bit SCOM address +/// +/// \param[in] prv A Pervasive Chiplet Id register (P0/P1) containing the +/// chiplet ID and multicast bit to use with the \a address +/// +/// \param[in] b The bit number of the bit to poll +/// +/// \param[in] count The number (count > 0) of times to poll for the bit. If +/// the bit is not set the \a count-th time the SCOM is read then the error +/// action occurs (see below). The maximum legal value is 0x1000000. +/// +/// \param[in] delay The number of PORE clock cycles (delay >= 0) to wait +/// between polls of the SCOM register. Specify a delay of 0 to avoid waiting +/// between polls. There is no waiting before the first poll, therefore the +/// WAIT is only executed \a count - 1 times in the worst case. The maximum +/// legal value is 0xffffff. The PORE engines run at nest / 4 normally, but at +/// the reference frequency during the early IPL. +/// +/// \param[in] error A branch target (symbol) in the event of error (see +/// below). +/// +/// This macro polls a SCOM register for a single set bit with a programmable +/// timeout, branching to an error handler in the event of a timeout. This +/// macro always uses the \c CTR register for the poll count. Therefore if +/// the CTR is currently in use the caller will need to save the current +/// contents of CTR to another register prior to invoking this macro. +/// +/// In the event of a polling timeout the code will branch to the \a +/// error target. Prior to the branch, the \a dest register will be loaded +/// with the PC to help diagnose the error. + + .macro pollbitset, dest:req, address:req, prv:req, b:req \ + count:req, delay:req, error:req + ..pollbit branz, (\dest), (\address), (\prv), (\b), \ + (\count), (\delay), (\error) + .endm + + +/// Poll for a bit to be clear in a SCOM register with timeout +/// +/// This macro is analogous to the pollbitset macro + + .macro pollbitclr, dest:req, address:req, prv:req, b:req \ + count:req, delay:req, error:req + ..pollbit braz, (\dest), (\address), (\prv), (\b), \ + (\count), (\delay), (\error) + .endm + + +// Implements pollbitset and pollbitclr - the only difference is 'branz' vs +// 'braz'. + + .macro ..pollbit, instr:req, dest:req, address:req, prv:req, b:req \ + count:req, delay:req, error:req + + .if (((\count) <= 0) || ((\count) > 0x1000000)) + .error "The poll count must satisfy 0 < count <= 0x1000000" + .endif + .if (((\delay) < 0) || ((\delay) >= 0x1000000)) + .error "The wait delay must satisfy 0 <= delay < 0x1000000" + .endif + + ls CTR, ((\count) - 1) + bra 7665249f +7665248: + .if ((\delay) != 0) + waits (\delay) + .endif +7665249: + ldandi (\dest), (\address), (\prv), BIT(\b) + \instr (\dest), 7665250f + loop 7665248b + mr (\dest), PC + braa (\error) +7665250: + + .endm + + +/// Test and branch if a bit is set in a data register +/// +/// \param[out] scratch This Data register (D0/D1) is destroyed to perform the +/// comparison. This may be the same as the \a data register if the \a data is +/// no longer needed after the comparison. +/// +/// \param[in] data This Data register (D0/D1) contains the data to be tested. +/// +/// \param[in] b The bit number (64-bit, big-endian) to test +/// +/// \param[in] target The branch target in the event that bit \a b is set in +/// \a data. + + .macro ifbitset, scratch:req, data:req, b:req, target:req + ..checkbits (\b) + andi (\scratch), (\data), BIT(\b) + branz (\scratch), (\target) + .endm + + +/// Test and branch is a bit is clear in a data register +/// +/// This macro is the bit-clear-test analogue of the ifbitset macro + + .macro ifbitclr, scratch:req, data:req, b:req, target:req + ..checkbits (\b) + andi (\scratch), (\data), BIT(\b) + braz (\scratch), (\target) + .endm + + +/// Read a SCOM register and branch if a bit is set +/// +/// \param[out] scratch This Data register (D0/D1) is destroyed to perform the +/// comparison. This may be the same as the \a data register if the \a data is +/// no longer needed after the comparison. +/// +/// \param[in] data This Data register (D0/D1) is first loaded from the SCOM +/// \a address, then tested for the bit being set. If \a scratch and \a data +/// are different register then this register will hold the original SCOM data +/// after the execution of the macro. +/// +/// \param[in] address A 32-bit SCOM address +/// +/// \param[in] prv A Pervasive Chiplet Id register (P0/P1) containing the +/// chiplet ID and multicast bit to use with the \a address +/// +/// \param[in] b The bit number (64-bit, big-endian) to test +/// +/// \param[in] target The branch target in the event that bit \a b is set in +/// \a data. + + .macro ifbitsetscom, scratch:req, data:req, address:req, prv:req, \ + b:req, target:req + ..checkbits (\b) + .if ((\scratch) == (\data)) + ldandi (\scratch), (\address), (\prv), BIT(\b) + .else + ld (\data), (\address), (\prv) + andi (\scratch), (\data), BIT(\b) + .endif + branz (\scratch), (\target) + .endm + + +/// Read a SCOM register and branch if a bit is clear +/// +/// This is the bit-clear-test analogue of the ifbitsetscom macro + + .macro ifbitclrscom, scratch:req, data:req, address:req, prv:req, \ + b:req, target:req + ..checkbits (\b) + .if ((\scratch) == (\data)) + ldandi (\scratch), (\address), (\prv), BIT(\b) + .else + ld (\data), (\address), (\prv) + andi (\scratch), (\data), BIT(\b) + .endif + braz (\scratch), (\target) + .endm + + +/// @} + +#endif // __ASSEMBLER__ + +#endif // __PORE_BITMANIP_H diff --git a/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/pore_inline.h b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/pore_inline.h new file mode 100644 index 000000000..a8436d69f --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/pore_inline.h @@ -0,0 +1,814 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/pore_inline.h $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +#ifndef __PORE_INLINE_H__ +#define __PORE_INLINE_H__ + +// $Id: pore_inline.h,v 1.15 2012/05/23 19:03:42 bcbrock Exp $ + +// ** WARNING : This file is maintained as part of the OCC firmware. Do ** +// ** not edit this file in the PMX area or the hardware procedure area ** +// ** as any changes will be lost. ** + +/// \file pore_inline.h +/// \brief Inline assembler for PORE code +/// +/// Note that this file defines several short macro symbols for register names +/// and other mnemonics used by inline assembly. For this reason it would +/// probably be best to only include this header when it was absolutely +/// necessary, i.e., only in C files that explicitly use inline assembly and +/// disassembly. + +#include <ctype.h> +#include <stddef.h> +#include <stdint.h> +#include "pgas.h" + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} /* So __cplusplus doesn't mess w/auto-indent */ +#endif + + +#ifndef __ASSEMBLER__ + +/// Error code strings from the PORE inline assembler/disassembler +/// +/// The PoreInlineContext object stores error codes that occur during +/// assembly as small integers. The '0' code indicates success. This is a +/// table of strings that describe the codes. It will be instantiated in +/// pore_inline.c + +extern const char *pore_inline_error_strings[]; + +#ifdef __PORE_INLINE_ASSEMBLER_C__ +const char *pore_inline_error_strings[] = { + "No error", + "The inline assembler memory is full, or disassembly has reached the end of the memory area", + "The instruction requires an ImD24 operand", + "The LC is not aligned or the instruction requires an aligned operand", + "The branch target is unreachable (too distant)", + "A register operand is illegal for the given instruction", + "The instruction form requires a signed 16-bit immediate", + "Valid rotate lengths are 1, 4, 8, 16 and 32", + "The instruction requires a 20-bit signed immediate", + "The instruction requires a 24-bit unsigned immediate", + "A parameter to pore_inline_context_create() is invalid", + "The instruction form requires an unsigned 22-bit immediate", + "This error is due to a bug in the PORE inline assembler (Please report)", + "The 'source' label for pore_inline_branch_fixup() is illegal", + "The 'source' instruction for pore_inline_branch_fixup() is not a branch", + "The disassembler does not recognize the instruction as a PORE opcode", + "Instruction parity error during disassembly", + "The string form of the disassembly is too long to represent (Please report)`", + "Use HALT instead of WAIT 0 if the intention is to halt.", + "A putative SCOM address is illegal (has non-0 bits where 0s are expected)." +}; +#endif /* __PORE_INLINE_ASSEMBLER_C__ */ + +#endif /* __ASSEMBLER__ */ + +#define PORE_INLINE_SUCCESS 0 +#define PORE_INLINE_NO_MEMORY 1 +#define PORE_INLINE_IMD24_ERROR 2 +#define PORE_INLINE_ALIGNMENT_ERROR 3 +#define PORE_INLINE_UNREACHABLE_TARGET 4 +#define PORE_INLINE_ILLEGAL_REGISTER 5 +#define PORE_INLINE_INT16_REQUIRED 6 +#define PORE_INLINE_ILLEGAL_ROTATE 7 +#define PORE_INLINE_INT20_REQUIRED 8 +#define PORE_INLINE_UINT24_REQUIRED 9 +#define PORE_INLINE_INVALID_PARAMETER 10 +#define PORE_INLINE_UINT22_REQUIRED 11 +#define PORE_INLINE_BUG 12 +#define PORE_INLINE_ILLEGAL_SOURCE_LC 13 +#define PORE_INLINE_NOT_A_BRANCH 14 +#define PORE_INLINE_UNKNOWN_OPCODE 15 +#define PORE_INLINE_PARITY_ERROR 16 +#define PORE_INLINE_DISASSEMBLY_OVERFLOW 17 +#define PORE_INLINE_USE_HALT 18 +#define PORE_INLINE_ILLEGAL_SCOM_ADDRESS 19 + + +/// Register name strings for the PORE inline assembler/disassembler + +extern const char *pore_inline_register_strings[16]; + +// C++ requires that these arrays of strings be declared 'const' to avoid +// warnings. But then you get warnings when the strings get stored into +// non-const variables. The solution is to rename these arrays inside the +// disassembler. If anyone has a better solution please let me know - Bishop + +#ifdef __PORE_INLINE_ASSEMBLER_C__ +const char* pore_inline_register_strings[16] = { + "P0", "P1", "A0", "A1", "CTR", "D0", "D1", "EMR", + "?", "ETR", "SPRG0", "?", "?", "?", "PC", "IFR" +}; +#endif /* __PORE_INLINE_ASSEMBLER_C__ */ + + +// Shorthand forms of constants defined in pgas.h, defined for consistency +// using the assembler-supported names. These constants are defined as an +// enum to avoid name conflicts with some firmware symbols when the PORE +// inline facility is used to create Host Boot procedures. + +enum { + + // Shorthand register mnemonics, defined as an enum to avoid name clashes. + + P0 = PORE_REGISTER_PRV_BASE_ADDR0, + P1 = PORE_REGISTER_PRV_BASE_ADDR1, + A0 = PORE_REGISTER_OCI_BASE_ADDR0, + A1 = PORE_REGISTER_OCI_BASE_ADDR1, + CTR = PORE_REGISTER_SCRATCH0, + D0 = PORE_REGISTER_SCRATCH1, + D1 = PORE_REGISTER_SCRATCH2, + EMR = PORE_REGISTER_ERROR_MASK, + ETR = PORE_REGISTER_EXE_TRIGGER, + SPRG0 = PORE_REGISTER_DATA0, + PC = PORE_REGISTER_PC, + IFR = PORE_REGISTER_IBUF_ID, + + // PgP IBUF_ID values + + PORE_GPE0 = PORE_ID_GPE0, + PORE_GPE1 = PORE_ID_GPE1, + PORE_SLW = PORE_ID_SLW, + PORE_SBE = PORE_ID_SBE, + + // Condition Codes + + CC_UGT = PORE_CC_UGT, + CC_ULT = PORE_CC_ULT, + CC_SGT = PORE_CC_SGT, + CC_SLT = PORE_CC_SLT, + CC_C = PORE_CC_C, + CC_V = PORE_CC_V, + CC_N = PORE_CC_N, + CC_Z = PORE_CC_Z, +}; + +// Pseudo-opcodes for LD/LDANDI/STD + +#define PORE_INLINE_PSEUDO_LD 0 +#define PORE_INLINE_PSEUDO_LDANDI 1 +#define PORE_INLINE_PSEUDO_STD 2 + + +// Private version of _BIG_ENDIAN + +#ifndef _BIG_ENDIAN +#define PORE_BIG_ENDIAN 0 +#else +#define PORE_BIG_ENDIAN _BIG_ENDIAN +#endif + + +/// Maximum size of disassembly strings +/// +/// This is currently sufficient for PORE_INLINE_LISTING_MODE. We don't want +/// to make this too long since the PoreInlineDisassembly object may be on the +/// stack in embedded applications. +#define PORE_INLINE_DISASSEMBLER_STRING_SIZE 128 + + +/// Generate PORE instruction parity +/// +/// This flag is an option to pore_inline_context_create(). If set, PORE +/// inline assembly sets the instruction parity bit for each assembled +/// instruction; otherwise the instruction parity bit is always 0. +#define PORE_INLINE_GENERATE_PARITY 0x01 + +/// Check PORE instruction parity +/// +/// This flag is an option to pore_inline_context_create(). If set, PORE +/// inline disassembly checks the instruction parity bit for each disassembled +/// instruction, failing with PORE_INLINE_PARITY_ERROR if the parify is not +/// correct. Otherwise the instruction parity bit is ignored during +/// disassembly. +#define PORE_INLINE_CHECK_PARITY 0x02 + +/// Disassemble in listing mode +/// +/// This flag is an option to pore_inline_context_create(). If set, then +/// generate disassembly strings in the form of a listing that contains +/// location counters and encoded instructions as well as their diassembly. +/// By default the disassembly strings do not contain this information and can +/// be fed back in as source code to a PORE assembler. +#define PORE_INLINE_LISTING_MODE 0x04 + +/// Disassemble in data mode +/// +/// This flag is an option to pore_inline_context_create(). If set, then +/// generate disassembly assuming that the context contains data rather than +/// text. Normally data is disassembled as .long directives, however if the +/// context is unaligned or of an odd length then .byte directives may be used +/// as well. This option can be used in conjunction with +/// PORE_INLINE_LISTING_MODE and PORE_INLINE_8_BYTE_DATA. +/// +/// Note: An intelligent application can switch between the default text +/// disassembly and data disassembly by manipulating the \a options field of +/// the PoreInlineContext between calls of pore_inline_disassemble(). +#define PORE_INLINE_DISASSEMBLE_DATA 0x08 + +/// Disassemble data in 8-byte format +/// +/// This flag is an option to pore_inline_context_create(). If set, then if +/// PORE_INLINE_DISASSEMBLE_DATA is also set then generate data disassembly as +/// 8-byte values rather then the default 4-byte values. Normally data is +/// disassembled as .quad directives under this option, however if the context +/// is unaligned or of an odd length then .long and .byte directives may be +/// used as well. This option can be used in conjunction with +/// PORE_INLINE_LISTING_MODE. +/// +/// Note: An intelligent application can switch between the default text +/// disassembly and data disassembly by manipulating the \a options field of +/// the PoreInlineContext between calls of pore_inline_disassemble(). +#define PORE_INLINE_8_BYTE_DATA 0x10 + + +#ifndef __ASSEMBLER__ + +/// The type of location counters for the PORE inline assembler + +typedef uint32_t PoreInlineLocation; + +/// PORE inline assembler context +/// +/// See the documentation page \ref pore_inline_assembler and the function +/// pore_inline_context_create() for futher details. + +typedef struct { + + /// The memory area to receive the inline assembly + /// + /// This field is never modified, allowing the *reset* APIs to function. + /// + /// Note: C++ does not allow arithmetic on void* objects, so we use the + /// Linux convention of storing memory addresses as type 'unsigned long'. + unsigned long memory; + + /// The original size of the memory area to receive the inline assembly + /// + /// This field is never modified, allowing the *reset* APIs to function. + size_t size; + + /// The original Location Counter (associated with \a memory) + /// + /// This field is never modified, allowing the *reset* APIs to function. + PoreInlineLocation original_lc; + + /// The memory address associated with the current LC + /// + /// Note: C++ does not allow arithmetic on void* objects, so we use the + /// Linux convention of storing memory addresses as type 'unsigned long'. + unsigned long lc_address; + + /// The remaining size of the memory area to receive the inline assembly + size_t remaining; + + /// The bytewise Location Counter of the assembled code + PoreInlineLocation lc; + + /// Inline assembly options + /// + /// This field is never modified, allowing the *reset* APIs to function. + int options; + + /// The last error code generated by the inline assembler + int error; + +} PoreInlineContext; + + +/// PORE inline disassembler result +/// +/// This object holds the disassembly produced by pore_inline_disassemble(). +/// See documentation for that function for complete details. + +typedef struct { + + /// The context as it existed when the instruction was assembled + /// + /// Disassembling an instruction modifies the context provided to + /// pore_inline_disassemble() to point to the next instruction. This + /// structure stores a copy of the context at the initial call of + /// pore_inline_disassemble(), that is, the context in effect when the + /// dissassembled instruction was assembled. + PoreInlineContext ctx; + + /// The first 32 bits of every instruction + uint32_t instruction; + + /// The opcode; bits 0..6 of the instruction + int opcode; + + /// A flag - If set the opcode is for a 12-byte instruction + int long_instruction; + + /// The parity bit; bit 7 of the instruction + int parity; + + /// The register specifier at bits 8..11 of the instruction + /// + /// This register is sometimes called the source, sometimes the target, + /// depending on the opcode. + int r0; + + /// The register specifier at bits 12..15 of the instruction + /// + /// This register is always called the 'source' but is named generically + /// here since sometimes the specifier at bits 8..11 is also called a + /// 'source'. + int r1; + + /// 'ImD16' is the signed 16-bit immediate for short immediate adds and + /// subtracts. For the rotate instruction this field also contains the + /// rotate count which is either 1, 4, 8, 16 or 32. + int16_t imd16; + + /// 'ImD20' is the 20-bit signed immediate for the LOAD20 instruction + int32_t imd20; + + /// 'ImD24' is the 24-bit unsigned immediate for the WAIT instruction + uint32_t imd24; + + /// 'ImD64' is the 64-bit immediate for data immediates and BRAI. This + /// field is only set for 3-word instructions. + uint64_t imd64; + + /// 'ImPCO20' is a signed, 20-bit word offset for branch instructions + int32_t impco20; + + /// 'ImPCO24' is a signed, 24-bit word offset for branch instructions + int32_t impco24; + + /// For imA24 opcodes, this indicates memory/pib (1/0) addressing.. + int memory_space; + + /// This is the base register specifier - either a memory (OCI) base + /// register or a pervasive base register - for Read/Write operations. + /// Note that this is a PORE register index, not simply 0/1. + int base_register; + + /// This is the 22-bit signed offset for memory (OCI) addressing. This + /// unsigned offset is added to a memory base register (A0/A1) to form the + /// final 32-bit address. + uint32_t memory_offset; + + /// This field contains the port number and local address portions of the + /// PIB/PCB address for load/store operations that target the PIB/PCB. + /// Note that bits 0..11 will always be 0 in this address. Bits 1..7 (the + /// multicast bit and chiplet id) are sourced from the associated + /// pervasive base register when the instruction executes. + uint32_t pib_offset; + + /// The update bit of the SCAND instruction + int update; + + /// The capture bit of the SCAND instruction + int capture; + + /// The scan length from a SCAND instruction + int scan_length; + + /// The scan select from a SCAND instruction + uint32_t scan_select; + + /// The address offset from a SCAND instruction + uint32_t scan_offset; + + /// The string form of the disassembly. + /// + /// The disassembly string is \e not terminated by a newline. In listing + /// mode the disassembly string \e will contain embedded newlines for long + /// instructions. + char s[PORE_INLINE_DISASSEMBLER_STRING_SIZE]; + + /// The data (for data disassembly) + /// + /// This is either 1 or 8 bytes in host byte order. + uint64_t data; + + /// The size of the disassembled \a data field (for data disassembly) + size_t data_size; + +} PoreInlineDisassembly; + + +// These are internal APIs - they are not needed by application code. + +void +pore_inline_be32(unsigned long p, uint32_t x); + +void +pore_inline_be64(unsigned long p, uint64_t x); + +uint32_t +pore_inline_host32(unsigned long p); + +uint64_t +pore_inline_host64(unsigned long p); + +int +pore_inline_parity(uint32_t instruction, uint64_t imd64); + +void +pore_inline_context_bump(PoreInlineContext *ctx, size_t bytes); + +int +pore_inline_instruction1(PoreInlineContext *ctx, int opcode, uint32_t operand); + +int +pore_inline_instruction3(PoreInlineContext *ctx, int opcode, uint32_t operand, + uint64_t imm); + +int +pore_inline_bra(PoreInlineContext *ctx, + int opcode, PoreInlineLocation target); + +int +pore_inline_brac(PoreInlineContext *ctx, + int opcode, int reg, PoreInlineLocation target); + +int +pore_inline_cmpibra(PoreInlineContext *ctx, + int opcode, int reg, + PoreInlineLocation target, uint64_t imm); + +int +pore_inline_brad(PoreInlineContext *ctx, int opcode, int reg); + +int +pore_inline_ilogic(PoreInlineContext *ctx, + int opcode, int dest, int src, uint64_t imm); +int +pore_inline_alurr(PoreInlineContext *ctx, + int opcode, int dest, int src1, int src2); + +int +pore_inline_adds(PoreInlineContext *ctx, + int opcode, int dest, int src, int imm); + +int +pore_inline_load_store(PoreInlineContext *ctx, + int opcode, int src_dest, int32_t offset, int base, + uint64_t imm); + + +// These are utility APIs that may be required by special-purpose code that +// uses the pore_inline library. + +void +pore_inline_decode_instruction(PoreInlineDisassembly* dis, + uint32_t instruction); + +void +pore_inline_decode_imd64(PoreInlineDisassembly* dis, uint64_t imd64); + + +// These are the inline PORE instructions, extended mnemonics and pseudo-ops +// to be used by application code. + +/// Set a location counter variable from a context +/// +/// This is a macro that sets the \a var (of type PoreInlineLocation) to the +/// current location counter of the \a ctx. The macro produces an expression +/// that evaluates to 0 so that it can be used in the logical-OR expressions +/// used to define inline assembly sequences. + +#define PORE_LOCATION(ctx, var) (((var) = (ctx)->lc), 0) + +int +pore_inline_context_create(PoreInlineContext *context, + void *memory, + size_t size, + PoreInlineLocation lc, + int options); + +void +pore_inline_context_reset(PoreInlineContext *context); + +void +pore_inline_context_reset_excursion(PoreInlineContext *context); + +void +pore_inline_context_copy(PoreInlineContext *dest, PoreInlineContext *src); + + +int +pore_inline_branch_fixup(PoreInlineContext *ctx, + PoreInlineLocation source, + PoreInlineLocation target); + + +int +pore_inline_disassemble(PoreInlineContext *ctx, PoreInlineDisassembly *dis); + + +// Native PORE instruction assembly, using PGAS opcode names and operand +// ordering rules. + +// NOP, TRAP, RET + +static inline int +pore_NOP(PoreInlineContext *ctx) +{ + return pore_inline_instruction1(ctx, PGAS_OPCODE_NOP, 0); +} + + +static inline int +pore_TRAP(PoreInlineContext *ctx) +{ + return pore_inline_instruction1(ctx, PGAS_OPCODE_TRAP, 0); +} + + +static inline int +pore_RET(PoreInlineContext *ctx) +{ + return pore_inline_instruction1(ctx, PGAS_OPCODE_RET, 0); +} + + +// WAITS, HALT, HOOKI + +int +pore_WAITS(PoreInlineContext *ctx, uint32_t cycles); + +static inline int +pore_HALT(PoreInlineContext *ctx) +{ + return pore_inline_instruction1(ctx, PGAS_OPCODE_WAITS, 0); +} + +int +pore_HOOKI(PoreInlineContext *ctx, uint32_t index, uint64_t imm); + + +// BRA, BSR, LOOP + +static inline int +pore_BRA(PoreInlineContext *ctx, PoreInlineLocation target) +{ + return pore_inline_bra(ctx, PGAS_OPCODE_BRA, target); +} + +static inline int +pore_BSR(PoreInlineContext *ctx, PoreInlineLocation target) +{ + return pore_inline_bra(ctx, PGAS_OPCODE_BSR, target); +} + +static inline int +pore_LOOP(PoreInlineContext *ctx, PoreInlineLocation target) +{ + return pore_inline_bra(ctx, PGAS_OPCODE_LOOP, target); +} + + +// BRAZ, BRANZ + +static inline int +pore_BRAZ(PoreInlineContext *ctx, int reg, PoreInlineLocation target) +{ + return pore_inline_brac(ctx, PGAS_OPCODE_BRAZ, reg, target); +} + + +static inline int +pore_BRANZ(PoreInlineContext *ctx, int reg, PoreInlineLocation target) +{ + return pore_inline_brac(ctx, PGAS_OPCODE_BRANZ, reg, target); +} + + +// CMPIBRAEQ, CMPIBRANE, CMPIBSREQ + +static inline int +pore_CMPIBRAEQ(PoreInlineContext *ctx, + int reg, PoreInlineLocation target, uint64_t imm) +{ + return pore_inline_cmpibra(ctx, PGAS_OPCODE_CMPIBRAEQ, reg, target, imm); +} + + +static inline int +pore_CMPIBRANE(PoreInlineContext *ctx, + int reg, PoreInlineLocation target, uint64_t imm) +{ + return pore_inline_cmpibra(ctx, PGAS_OPCODE_CMPIBRANE, reg, target, imm); +} + + +static inline int +pore_CMPIBSREQ(PoreInlineContext *ctx, + int reg, PoreInlineLocation target, uint64_t imm) +{ + return pore_inline_cmpibra(ctx, PGAS_OPCODE_CMPIBSREQ, reg, target, imm); +} + + +// BRAD, BSRD + +static inline int +pore_BRAD(PoreInlineContext *ctx, int reg) { + return pore_inline_brad(ctx, PGAS_OPCODE_BRAD, reg); +} + +static inline int +pore_BSRD(PoreInlineContext *ctx, int reg) { + return pore_inline_brad(ctx, PGAS_OPCODE_BSRD, reg); +} + + +// ANDI, ORI, XORI + +static inline int +pore_ANDI(PoreInlineContext *ctx, int dest, int src, uint64_t imm) +{ + return pore_inline_ilogic(ctx, PGAS_OPCODE_ANDI, dest, src, imm); +} + +static inline int +pore_ORI(PoreInlineContext *ctx, int dest, int src, uint64_t imm) +{ + return pore_inline_ilogic(ctx, PGAS_OPCODE_ORI, dest, src, imm); +} + +static inline int +pore_XORI(PoreInlineContext *ctx, int dest, int src, uint64_t imm) +{ + return pore_inline_ilogic(ctx, PGAS_OPCODE_XORI, dest, src, imm); +} + + +// AND, OR, XOR, ADD, SUB + +static inline int +pore_AND(PoreInlineContext *ctx, int dest, int src1, int src2) +{ + return pore_inline_alurr(ctx, PGAS_OPCODE_AND, dest, src1, src2); +} + +static inline int +pore_OR(PoreInlineContext *ctx, int dest, int src1, int src2) +{ + return pore_inline_alurr(ctx, PGAS_OPCODE_OR, dest, src1, src2); +} + +static inline int +pore_XOR(PoreInlineContext *ctx, int dest, int src1, int src2) +{ + return pore_inline_alurr(ctx, PGAS_OPCODE_XOR, dest, src1, src2); +} + +static inline int +pore_ADD(PoreInlineContext *ctx, int dest, int src1, int src2) +{ + return pore_inline_alurr(ctx, PGAS_OPCODE_ADD, dest, src1, src2); +} + +static inline int +pore_SUB(PoreInlineContext *ctx, int dest, int src1, int src2) +{ + return pore_inline_alurr(ctx, PGAS_OPCODE_SUB, dest, src1, src2); +} + + +// ADDS, SUBS + +static inline int +pore_ADDS(PoreInlineContext *ctx, int dest, int src, int imm) +{ + return pore_inline_adds(ctx, PGAS_OPCODE_ADDS, dest, src, imm); +} + +static inline int +pore_SUBS(PoreInlineContext *ctx, int dest, int src, int imm) +{ + return pore_inline_adds(ctx, PGAS_OPCODE_SUBS, dest, src, imm); +} + + +// NEG, MR, ROLS, LS, LI + +int +pore_NEG(PoreInlineContext *ctx, int dest, int src); + +int +pore_MR(PoreInlineContext *ctx, int dest, int src); + +int +pore_ROLS(PoreInlineContext *ctx, int dest, int src, int imm); + +int +pore_LS(PoreInlineContext *ctx, int dest, int imm); + +int +pore_LI(PoreInlineContext *ctx, int dest, uint64_t imm); + + +// LD, LDANDI, STD, STI, BSI, BCI + +static inline int +pore_LD(PoreInlineContext *ctx, int dest, int32_t offset, int base) +{ + return + pore_inline_load_store(ctx, + PORE_INLINE_PSEUDO_LD, dest, offset, base, 0); +} + +static inline int +pore_LDANDI(PoreInlineContext *ctx, + int dest, int32_t offset, int base, uint64_t imm) +{ + return + pore_inline_load_store(ctx, + PORE_INLINE_PSEUDO_LDANDI, + dest, offset, base, imm); +} + +static inline int +pore_STD(PoreInlineContext *ctx, int src, int32_t offset, int base) +{ + return + pore_inline_load_store(ctx, + PORE_INLINE_PSEUDO_STD, src, offset, base, 0); +} + +static inline int +pore_STI(PoreInlineContext *ctx, int32_t offset, int base, uint64_t imm) +{ + return + pore_inline_load_store(ctx, + PGAS_OPCODE_STI, 0, offset, base, imm); +} + +static inline int +pore_BSI(PoreInlineContext *ctx, + int src, int32_t offset, int base, uint64_t imm) +{ + return + pore_inline_load_store(ctx, + PGAS_OPCODE_BSI, src, offset, base, imm); +} + +static inline int +pore_BCI(PoreInlineContext *ctx, + int src, int32_t offset, int base, uint64_t imm) +{ + return + pore_inline_load_store(ctx, + PGAS_OPCODE_BCI, src, offset, base, imm); +} + + +// BRAIA + +int +pore_BRAIA(PoreInlineContext *ctx, + uint16_t address_space, uint32_t offset); + + +// SCAND + +int +pore_SCAND(PoreInlineContext *ctx, + int update, int capture, uint16_t length, + uint32_t select, uint32_t offset); + +#endif /* __ASSEMBLER__ */ + +#if 0 +{ /* So __cplusplus doesn't mess w/auto-indent */ +#endif +#ifdef __cplusplus +} +#endif + +#endif /* __PORE_INLINE_H__ */ + diff --git a/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/pore_inline_assembler.c b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/pore_inline_assembler.c new file mode 100644 index 000000000..ec4f0abbf --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/pore_inline_assembler.c @@ -0,0 +1,1487 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/pore_inline_assembler.c $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +// $Id: pore_inline_assembler.c,v 1.14 2012/05/23 19:03:42 bcbrock Exp $ + +// ** WARNING : This file is maintained as part of the OCC firmware. Do ** +// ** not edit this file in the PMX area or the hardware procedure area ** +// ** as any changes will be lost. ** + +/// \file pore_inline_assembler.c +/// \brief Inline PGAS assembler for PgP/Stage1 PORE +/// +/// \page pore_inline_assembler PORE Inline Assembler and Disassembler +/// +/// Several procedures targeting the PORE engine require inline assembly and +/// disassembly of PORE code, that is, they require that PORE instructions be +/// assembled/disassembled directly into/from a host memory buffer. This page +/// describes these facilities. The APIs described here are implemented in +/// the files pore_inline.h, pore_inline_assembler.c and +/// pore_inline_disassembler.c. Both the inline assembelr and disassembler +/// conform to the PGAS assembly format for PORE. +/// +/// Both inline assembly and disassembly make use of a PoreInlineContext +/// structure. This structure represents the state of a memory area being +/// targeted for inline assembly and disassembly. The context is initialized +/// with the pore_inline_context_create() API, and a pointer to an instance of +/// this structure appears as the first argument of all assembler/disassembler +/// APIs. As assembly/disassembly progresses the PoreInlineContext keeps +/// track of how much host memory area has been filled by assembled code or +/// scanned by the disassebler. +/// +/// Assembler/disassembler APIs are predicates that return 0 for success and a +/// non-zero error code for failure. In the event of failure, the error code +/// (a small integer) is also stored in the \a error field of the context +/// structure. String forms of the error codes are also available in the +/// global array pore_inline_error_strings[]. +/// +/// The assembler always produces PORE code in the PORE-native big-endian +/// format. Likewise, the diassembler assumes the host memory to be +/// disassembled contains PORE code in big-endian format. +/// +/// \section Initialization +/// +/// Before invoking inline assembly/disassembly APIs, an instance of a +/// PoreInlineContext structure must be initialized using the +/// pore_inline_context_create() API. For assembly, the context describes the +/// host memory buffer that will contain the assembled code. For disassembly, +/// the context describes the host memory area that contains the code to be +/// disassembled. Full documentation is available for +/// pore_inline_context_create(), including documentation for options that +/// control assembly and disassembly. The implementation also provides a +/// 'copy operator' for the context, pore_inline_context_copy(). +/// +/// An example of initializing a context for inline assembly with parity +/// checking appears below. +/// +/// \code +/// +/// PoreInlineContext ctx; +/// uint32_t buf[BUFSIZE]; +/// +/// rc = pore_inline_context_create(&ctx, buf, BUFSIZE * 4, 0, +/// PORE_INLINE_CHECK_PARITY); +/// if (rc) . . . Handle Error +/// +/// \endcode +/// +/// Applications that reuse the same memory buffer for assembling and +/// processing multiple PORE programs can 'reset' the context between uses by +/// using the pore_inline_context_reset() API. pore_inline_context_reset() +/// resets the location counter and memory extent to their initial (creation) +/// values, and the context error code is cleared. Any options specified at +/// creation remain as they were. +/// +/// \section Assembler +/// +/// The inline assembler implements each PORE/PGAS instruction as individual +/// function calls. The APIs are consistently named \c pore_<OPCODE>, where +/// \c <OPCODE> is a PGAS mnemonic in upper case. The arguments to each +/// opcode appear in the same order that they appear in the source-level +/// assembler, with appropriate C-language types. The supported opcode APIs +/// are defined in pore_inline.h +/// +/// Since the PORE instruction APIs are effectivly predicates, linear code +/// sequences are easily assembled using the C-language logical OR construct. +/// Any non-0 return code will immediatly break the sequence and set the +/// expression value to 1. The failure code can then be recovered from the \a +/// error field of the context. This coding technique is illustrated in the +/// following example of assembling a memory-memory copy sequence. +/// +/// \code +/// +/// PoreInlineContext ctx; +/// int error; +/// +/// . . . // Initialize context +/// +/// error = +/// pore_LD(&ctx, D0, 0, A0) || +/// pore_STD(&ctx, D0, 0, A1); +/// +/// if (error) <. . . Handle error based on ctx.error> +/// +/// \endcode +/// +/// The above example generates code equivalent to +/// +/// \code +/// +/// ld D0, 0, A0 +/// std D0, 0, A1 +/// +/// \endcode +/// +/// Again, if an error were to occur during assembly, inline assembly would +/// stop (and the logical OR would terminate) at the point of failure. In +/// particular, the inline assembler will never allow assembled code to exceed +/// the bounds of the memory area defined by the initial call of +/// pore_inline_context_create() that defines the assembler memory space. +/// +/// +/// \subsection Register Names and Other Mnemonics +/// +/// The header file pore_inline.h defines macros for the register mnemonics. +/// +/// - D0, D1 : 64-bit data registers +/// - A0, A1 : 32-bit address registers +/// - P0, P1 : 7-bit Pervasive chiplet id registers +/// - CTR : 24-bit ounter register +/// - PC : 48-bit Program Counter +/// - ETR : 64-bit EXE-Trigger Register (Low-order 32 bits are writable) +/// - EMR : The Error Mask Register +/// - IFR : ID/Flags Register +/// - SPRG0 : 32-bit Special-Purpose General Register 0 +/// +/// Mnemonics for the condition code bits are also defined by pore_inline.h +/// using the PGAS mnemonics. +/// +/// +/// \subsection Assembling Branches +/// +/// Opcodes that implement relative branches require that the branch target be +/// specified as a <em> location counter <\em>. Once initialized, the current +/// location counter is available as the \a lc field of the PoreInlineContext +/// object controlling the assembly. The \a lc field is the only field +/// (besides the error code held in the \a error field) that application code +/// should ever reference. The inline assembler also provides a typedef +/// PoreInlineLocation to use for location counters, as well as the macro +/// PORE_LOCATION() to define a location variable inline with the code flow. +/// +/// \subsubsection Backward Branches +/// +/// Backward branches are straightforward. For example, the memory-memory +/// copy example from earlier can be converted into a loop as shown below. The +/// \a loop_target variable is initialized with the location counter of the +/// first instruction of the loop. The final instruction of the loop then +/// branches back to the \a loop_target. +/// +/// \code +/// +/// PoreInlineContext ctx; +/// PoreInlineLocation loop_target = 0; // See ** below the example +/// int error; +/// +/// . . . // Initialize context +/// +/// error = +/// PORE_LOCATION(&ctx, loop_target) || +/// pore_LD(&ctx, D0, 0, A0) || +/// pore_STD(&ctx, D0, 0, A1) || +/// pore_ADDS(&ctx, A0, A0, 8) || +/// pore_ADDS(&ctx, A1, A1, 8) || +/// pore_LOOP(&ctx, loop_target); +/// +/// if (error) <. . . Handle error based on ctx.error> +/// +/// \endcode +/// +/// The above inline assembler sequence is equivalent to the PGAS code +/// sequence: +/// +/// \code +/// +/// loop_target: +/// ld D0, 0, A0 +/// std D0, 0, A1 +/// adds A0, A0, 8 +/// adds A1, A1, 8 +/// loop loop_target +/// +/// \endcode +/// +/// ** Location counters used as loop targets may need to be initialized, +/// otherwise the compiler may issue a warning that the variable "may be used +/// uninitialized", although in well-written code this would never happen. +/// +/// +/// \subsubsection Forward Branches +/// +/// Forward branches are more complex. Since the target location counter is +/// not known until the target has been assembled, the inline assembler +/// provides the API pore_inline_branch_fixup() to fix up forward branches +/// once the actual target is known. This is illustrated in the simple code +/// sequence below, where an instruction is conditionally skipped. +/// +/// \code +/// +/// PoreInlineContext ctx; +/// PoreInlineLocation source = 0, target = 0; +/// int error, rc; +/// +/// . . . // Initialize context +/// +/// error = +/// PORE_LOCATION(&ctx, source) || +/// pore_BRANZ(&ctx, D0, source) || +/// pore_ADDS(&ctx, D1, D1, 1) || +/// PORE_LOCATION(&ctx, target) || +/// pore_LD(&ctx, D0, 0, A0); +/// +/// if (error) <. . . Handle assembly error based on ctx->error> +/// rc = pore_inline_branch_fixup(&ctx, source, target); +/// if (rc) <. . . Handle branch fixup error> +/// +/// \endcode +/// +/// In the above code, the branch instruction is initially assembled as a +/// branch-to-self - the recommended idiom for forward branch source +/// instructions. Once the entire sequence has been assembled, +/// pore_inline_branch_fixup() reassembles the \c source instruction as a +/// branch to the \target instruction. The above instruction sequence is +/// equivalent to the PGAS code below: +/// +/// \code +/// +/// source: +/// branz D0, target +/// adds D1, D1, 1 +/// target: +/// ld D0, 0, A0 +/// +/// \endcode +/// +/// +/// \subsubsection Absolute Branches +/// +/// It is unlikely that a typical application of the PORE inline assembler +/// would ever need to include an absolute branch, since the branch target in +/// this case is a fixed absolute address that must be known at assembly +/// time. However the inline assembler does provide the pore_BRAIA() API for +/// this purpose. This opcode requires a 16-bit address space constant and a +/// 32-bit absoulte address (offset) within the memory space to specify the +/// branch. +/// +/// +/// \section Disassembly +/// +/// Inline disassembly is implemented by a single API, +/// pore_inline_disassemble(). The idea is similar to assembly: A host memory +/// context containing PORE code (or data) is described by a PoreInlineContext +/// structure. Each call of pore_inline_disassemble() disassembles the next +/// instruction (or datum) in the context into a PoreInlineDisassembly +/// structure provided by the caller. The disassembly object contains both +/// binary and string forms of the disassembled instruction (or data). The +/// next call of pore_inline_disassemble() proceses the next instruction (or +/// datum) and so on. +/// +/// \subsection Text (Code) Disassembly +/// +/// In the example below the inline disassembler is used to completely +/// disassemble a memory area containing text (code) to \a stdout until an +/// error occurs, assumed to be either due to disassembling the entire memory +/// area or finding an illegal instruction. +/// +/// \code +/// +/// PoreInlineContext ctx; +/// PoreInlineDisassembly dis; +/// +/// . . . // Initialize context +/// +/// while (pore_inline_disassemble(&ctx, &dis) == 0) { +/// printf("%s\n", dis.s); +/// } +/// +/// \endcode +/// +/// To illustrate binary disassembly, the following example uses the +/// disassembler to search for a RET statement in a block of PORE code, in +/// order to extend an inline subroutine with more code. Note that the field +/// \a dis->ctx contains the context that existed at the time the instruction +/// was assembled. By copying this context back into the global context, +/// inline assembly will continue by overwriting the RET with new +/// instructions. If the copy had \e not been done, then newly assembled code +/// would have \e followed the RET. +/// +/// \code +/// +/// PoreInlineContext ctx; +/// PoreInlineDisassembly dis; +/// +/// . . . // Initialize context +/// +/// while ((pore_inline_disassemble(&ctx, &dis) == 0) && +/// (dis.opcode != PORE_OPCODE_RET)); +/// if (ctx.error != 0) { +/// . . . // Handle error +/// } else { +/// pore_inline_context_copy(&ctx, &dis.ctx); +/// . . . // Continue assembly by overwriting the RET +/// } +/// +/// \endcode +/// +/// A special type of context reset is available to simplify applications that +/// need to disassemble a just-assembled code sequence, e.g. for debugging. +/// pore_inline_context_reset_excursion() resets the context such that the +/// effective size of the context only covers the just-assembled code, +/// allowing a dissassembly loop to cleanly stop once all code has been +/// disassembled. The use is illustrated below - note that the disassembly +/// stops on the expected error code PORE_INLINE_NO_MEMORY once the +/// (effective) end of the buffer is reached. +/// +/// \code +/// +/// PoreInlineContext ctx; +/// PoreInlineDisassembly dis; +/// +/// . . . // Initialize context +/// . . . // Assemble code into context +/// +/// pore_inline_context_reset_excursion(&ctx); +/// +/// while (pore_inline_disassemble(&ctx, &dis) == 0) { +/// printf("%s\n", dis.s); +/// } +/// if (ctx.error != PORE_INLINE_NO_MEMORY) { +/// . . . // Handle error +/// } +/// +/// \endcode +/// +/// \subsection Data Disassembly +/// +/// If the PoreInlineContext is created with the flag +/// PORE_INLINE_DISASSEMBLE_DATA, then the context is disassembled as +/// data. For complete information see the documentation for +/// pore_inline_disassemble(). + + +#define __PORE_INLINE_ASSEMBLER_C__ +#include "pore_inline.h" +#undef __PORE_INLINE_ASSEMBLER_C__ + +// Definitions of PORE register classes. These are predicates that return +// 1 if the register is a member of the class, else 0. + +static int +pore_data(int reg) +{ + return + (reg == D0) || + (reg == D1); +} + + +static int +pore_address(int reg) +{ + return + (reg == A0) || + (reg == A1); +} + + +static int +pore_pervasive_chiplet_id(int reg) +{ + return + (reg == P0) || + (reg == P1); +} + + +static int +pore_branch_compare_data(int reg) +{ + return + (reg == D0) || + (reg == D1) || + (reg == CTR); +} + + +static int +pore_ls_destination(int reg) +{ + return + (reg == D0) || + (reg == D1) || + (reg == A0) || + (reg == A1) || + (reg == P0) || + (reg == P1) || + (reg == CTR); +} + + +static int +pore_li_destination(int reg) +{ + return + (reg == D0) || + (reg == D1) || + (reg == A0) || + (reg == A1) || + (reg == P0) || + (reg == P1) || + (reg == CTR); +} + + +static int +pore_mr_source(int reg) +{ + return + (reg == D0) || + (reg == D1) || + (reg == A0) || + (reg == A1) || + (reg == P0) || + (reg == P1) || + (reg == CTR) || + (reg == PC) || + (reg == ETR) || + (reg == SPRG0) || + (reg == IFR) || + (reg == EMR); +} + +static int +pore_mr_destination(int reg) +{ + return + (reg == D0) || + (reg == D1) || + (reg == A0) || + (reg == A1) || + (reg == P0) || + (reg == P1) || + (reg == CTR) || + (reg == PC) || + (reg == SPRG0)|| + (reg == EMR); +} + + +/// Portable store of a 32-bit integer in big-endian format +/// +/// The address \a p to receive the data is in the form of an unsigned long. + +void +pore_inline_be32(unsigned long p, uint32_t x) +{ + uint8_t *p8 = (uint8_t *)p; + uint8_t *px = (uint8_t *)(&x); + int i, j; + + if (!PORE_BIG_ENDIAN) { + for (i = 0, j = 3; i < 4; i++, j--) { + p8[i] = px[j]; + } + } else { + *((uint32_t *)p) = x; + } +} + + +/// Portable store of a 64-bit integer in big-endian format +/// +/// The address \a p to receive the data is in the form of an unsigned long. + +void +pore_inline_be64(unsigned long p, uint64_t x) +{ + uint8_t *p8 = (uint8_t *)p; + uint8_t *px = (uint8_t *)(&x); + int i, j; + + if (!PORE_BIG_ENDIAN) { + for (i = 0, j = 7; i < 8; i++, j--) { + p8[i] = px[j]; + } + } else { + *((uint64_t *)p) = x; + } +} + + +// Portable load of a 32-bit integer in big-endian format + +uint32_t +pore_inline_host32(unsigned long p) +{ + uint32_t x; + uint8_t *p8 = (uint8_t *)p; + uint8_t *px = (uint8_t *)(&x); + int i, j; + + if (!PORE_BIG_ENDIAN) { + for (i = 0, j = 3; i < 4; i++, j--) { + px[j] = p8[i]; + } + } else { + x = *((uint32_t *)p); + } + + return x; +} + + +// Portable load of a 64-bit integer in big-endian format + +uint64_t +pore_inline_host64(unsigned long p) +{ + uint64_t x; + uint8_t *p8 = (uint8_t *)p; + uint8_t *px = (uint8_t *)(&x); + int i, j; + + if (!PORE_BIG_ENDIAN) { + for (i = 0, j = 7; i < 8; i++, j--) { + px[j] = p8[i]; + } + } else { + x = *((uint64_t *)p); + } + + return x; +} + + +// 32-bit population count +// +// This is a well-known divide-and-conquer algorithm, e.g. look on Wikipedia +// under "Hamming Weight". The idea is to compute sums of adjacent bit +// segments in parallel, in place. + +static int +popcount32(uint32_t x) +{ + uint32_t m1 = 0x55555555; + uint32_t m2 = 0x33333333; + uint32_t m4 = 0x0f0f0f0f; + x -= (x >> 1) & m1; /* Sum pairs of bits */ + x = (x & m2) + ((x >> 2) & m2);/* Sum 4-bit segments */ + x = (x + (x >> 4)) & m4; /* Sum 8-bit segments */ + x += x >> 8; /* Sum 16-bit segments */ + return (x + (x >> 16)) & 0x3f; /* Final sum */ +} + + +// 64-bit population count + +static int +popcount64(uint64_t x) +{ + return popcount32(x & 0xffffffff) + popcount32(x >> 32); +} + + +// Compute the parity of a PORE instruction as 0 or 1 + +int +pore_inline_parity(uint32_t instruction, uint64_t imd64) +{ + return (popcount32(instruction) + popcount64(imd64)) % 2; +} + + +/// Reset a PORE inline assembler context to its creation state +/// +/// \param ctx A pointer to an initialized (and likely 'used') +/// PoreInlineContext object. +/// +/// This API resets a PoreInlineContext object to it's \e creation state, that +/// is, the state it was in after the call of pore_inline_context_create(). +/// This API is designed for applications that reuse a memory buffer to +/// assemble multiple PORE code sequences. After each sequence has been fully +/// assembled and processed, calling pore_inline_context_reset() sets the +/// context back as it was when the context was initially created so that the +/// memory area can be reused. In particular, this API resets the location +/// counter and memory extent to their initial values, and the error code is +/// cleared. Any options specified at creation remain as they were. +/// +/// For a slightly different type of reset, see +/// pore_inline_context_reset_excursion(). + +void +pore_inline_context_reset(PoreInlineContext *ctx) +{ + ctx->lc_address = ctx->memory; + ctx->remaining = ctx->size; + ctx->lc = ctx->original_lc; + ctx->error = 0; +} + + + +/// Reset a PORE inline assembler context to a special state for disassembly +/// +/// \param ctx A pointer to an initialized (and almost certainly 'used') +/// PoreInlineContext object. +/// +/// This API resets a PoreInlineContext object to it's \e creation state, that +/// is, the state it was in after the call of pore_inline_context_create(), \e +/// except that the effective size of the memory area has been reduced to the +/// size that was actually used during assembly. This API is designed for +/// applications that assemble into a memory buffer and then want to easily +/// disassemble the code (e.g., for debugging). After a code sequence has +/// been assembled, calling pore_inline_context_reset_excursion() sets the +/// context back as it was when the context was initially created, but with a +/// (typically) shorter effective length, so that the disassembly will cleanly +/// stop once the entire sequence has been disassembled. Once disassembled, +/// the buffer can be fully resued after a subsequent call of +/// pore_inline_context_reset(). In particular, this API resets the location +/// counter to its initial value, clears the error code, and sets the +/// effective size of the context to the amount of memory currently used. Any +/// options specified at creation remain as they were. +/// +/// For a full context reset see pore_inline_context_reset(). For an example +/// see the \b Disassembly section of \ref pore_inline_assembler. + +void +pore_inline_context_reset_excursion(PoreInlineContext *ctx) +{ + ctx->lc_address = ctx->memory; + ctx->remaining = ctx->size - ctx->remaining; + ctx->lc = ctx->original_lc; + ctx->error = 0; +} + + +/// Create a PORE inline assembler context +/// +/// \param ctx A pointer to a PoreInlineContext object to be initialized +/// and used for inline assembly. or disassembly. +/// +/// \param memory A pointer to the host memory area to receive the assembled +/// code, or contain the code to disassemble. In general the inline assembler +/// will expect this memory area to be 4-byte aligned. This pointer may be +/// NULL (0) only if the associated \a size is also 0. +/// +/// \param size The size (in bytes) of the host memory area. The inline +/// assembler will generate the PORE_INLINE_NO_MEMORY error if an attempt is +/// made to assemble an instruction that would overflow the buffer, or +/// disassemble past the end of the buffer. A 0 size is valid. +/// +/// \param lc The initial, bytewise, target location counter for the assembled +/// or disassembled code. This paramater will normally be initialized to 0 for +/// assembling relocatable programs. The parameter would only need to be +/// specified as non-0 for special cases, such as creating a context for +/// disassembly. +/// +/// \param options Option flags. Option flags are OR-ed together to create +/// the final set of options. Valid options are +/// +/// - PORE_INLINE_GENERATE_PARITY : Generate the proper parity bit for each +/// instruction during assembly. +/// +/// - PORE_INLINE_CHECK_PARITY : Check for correct instruction parity during +/// disassembly. +/// +/// - PORE_INLINE_LISTING_MODE : Generate disassembly strings in the form of a +/// listing that contains location counters and encoded instructions as well +/// as their diassembly. By default the disassembly strings do not contain +/// this information and can be fed back in as source code to a PORE +/// assembler. +/// +/// - PORE_INLINE_DISASSEMBLE_DATA : generate disassembly assuming that the +/// context contains data rather than text. Normally data is disassembled as +/// .long directives, however if the context is unaligned or of an odd length +/// then .byte directives may be used as well. This option can be used in +/// conjunction with PORE_INLINE_LISTING_MODE. +/// +/// - PORE_INLINE_8_BYTE_DATA : generate data disassembly using 8-byte values +/// rather than the default 4-byte values. text. Normally data is +/// disassembled as .quad directives, however if the context is unaligned or +/// of an odd length then .long and .byte directives may be used as well. +/// This option can be used in conjunction with PORE_INLINE_LISTING_MODE. +/// +/// A PoreInlineContext describes a memory area and assembler context for +/// inline assembly and disassembly. Assembly/disassembly begins at the host +/// memory location and virtual location counter described in the parameters. +/// As instructions are assembled/disassembled the PoreInlineContext keeps +/// track of where in the host memory and virtual PORE memory areas to place +/// new instructions during assembly, or from where to fetch the next +/// instruction to disassemble. +/// +/// \retval 0 Success +/// +/// \retval PORE_INLINE_INVALID_PARAMETER Either the \a context pointer is +/// NULL (0), the \a memory pointer is NULL (0) with a non-0 size, or the \a +/// options include invalid options. The error code is also stored as the +/// value of ctx->error, and in the event of an error the ctx->size field is +/// set to 0, effectively preventing the context from being used. + +int +pore_inline_context_create(PoreInlineContext *ctx, + void *memory, size_t size, + PoreInlineLocation lc, int options) +{ + int rc; + + int valid_options = + PORE_INLINE_GENERATE_PARITY | + PORE_INLINE_CHECK_PARITY | + PORE_INLINE_LISTING_MODE | + PORE_INLINE_DISASSEMBLE_DATA; + + if ((ctx == 0) || ((memory == 0) && (size != 0)) || + ((options & ~valid_options) != 0)) { + rc = PORE_INLINE_INVALID_PARAMETER; + ctx->size = 0; /* Effectively prevents using the ctx */ + } else { + rc = 0; + ctx->memory = (unsigned long)memory; + ctx->size = size; + ctx->original_lc = lc; + ctx->options = options; + pore_inline_context_reset(ctx); + } + + ctx->error = rc; + return rc; +} + + +/// Copy a PORE inline assembler context +/// +/// \param dest A pointer to a PoreInlineContext object to be initialized +/// as a copy of the \a src context. +/// +/// \param src A pointer to a PoreInlineContext object to be used as the +/// source of the copy. +/// +/// This API copies one PoreInlineContext structure to another. An example +/// use appears in \ref pore_inline_assembly in the section discussing +/// disassembly. + +void +pore_inline_context_copy(PoreInlineContext *dest, PoreInlineContext *src) +{ + *dest = *src; +} + + +// 'Bump' a context forward by a given number of bytes. This an internal API +// and the bump is always known to be legal. + +void +pore_inline_context_bump(PoreInlineContext *ctx, size_t bytes) +{ + ctx->remaining -= bytes; + ctx->lc += bytes; + ctx->lc_address += bytes; +} + + +// Allocate space in the inline assembler context +// +// Allocation is specified and implemented in bytes. Both the physical +// memory and the virtual LC are required to be 4-byte aligned. The allocator +// returns a pointer to the memory area, or 0 if allocation fails. +// Allocation failure sets the context error code to either +// PORE_INLINE_NO_MEMORY or PORE_INLINE_ALIGNMENT_ERROR. + +static unsigned long +pore_inline_allocate(PoreInlineContext *ctx, size_t bytes) +{ + unsigned long p = 0; + + if (((ctx->lc % 4) != 0) || + ((ctx->lc_address % 4) != 0)) { + ctx->error = PORE_INLINE_ALIGNMENT_ERROR; + + } else if (bytes > ctx->remaining) { + ctx->error = PORE_INLINE_NO_MEMORY; + + } else { + p = ctx->lc_address; + pore_inline_context_bump(ctx, bytes); + } + return p; +} + + +// Assemble a 1-word instruction +// +// The opcode and operand are assumed to be legal, having come from +// abstractions that check their arguments. This call may fail with +// PORE_INLINE_NO_MEMORY if there is no more room in the memory buffer. A +// non-zero return indicates failure. + +int +pore_inline_instruction1(PoreInlineContext *ctx, int opcode, uint32_t operand) +{ + uint32_t instruction; + unsigned long p; + + p = pore_inline_allocate(ctx, 4); + if (p != 0) { + + instruction = (opcode << 25) | operand; + if (ctx->options & PORE_INLINE_GENERATE_PARITY) { + instruction |= (1 - pore_inline_parity(instruction, 0)) << 24; + } + + pore_inline_be32(p, instruction); + ctx->error = 0; + } + return p == 0; +} + + +// Assemble a 3-word instruction +// +// The opcode and operand are assumed to be legal, having come from +// abstractions that check their arguments. This call may fail with +// PORE_INLINE_NO_MEMORY if there is no more room in the memory buffer. A +// non-zero return indicates failure. + +int +pore_inline_instruction3(PoreInlineContext *ctx, int opcode, uint32_t operand, + uint64_t immediate) +{ + uint32_t instruction; + unsigned long p; + + p = pore_inline_allocate(ctx, 12); + if (p != 0) { + + instruction = (opcode << 25) | operand; + if (ctx->options & PORE_INLINE_GENERATE_PARITY) { + instruction |= (1 - pore_inline_parity(instruction, immediate)) << 24; + } + + pore_inline_be32(p, instruction); + pore_inline_be64(p + 4, immediate); + ctx->error = 0; + } + return p == 0; +} + + +// Assemble WAIT +// +// The cycle count must be an unsigned 24-bit immediate otherwise the error +// PORE_INLINE_UINT24_REQUIRED is signalled. PGAS requires that HALT be used +// if the intention is to halt + +int +pore_WAITS(PoreInlineContext *ctx, uint32_t cycles) +{ + uint32_t operand; + int opcode = PGAS_OPCODE_WAITS; + + if (cycles == 0) { + ctx->error = PORE_INLINE_USE_HALT; + } else if ((cycles & 0xffffff) != cycles) { + ctx->error = PORE_INLINE_UINT24_REQUIRED; + } else { + operand = cycles; + pore_inline_instruction1(ctx, opcode, operand); + } + return ctx->error; +} + + +// Assemble HOOKI +// +// The hook index must be an unsigned 24-bit immediate otherwise the error +// PORE_INLINE_UINT24_REQUIRED is signalled. + +int +pore_HOOKI(PoreInlineContext *ctx, uint32_t index, uint64_t imm) +{ + uint32_t operand; + int opcode = PGAS_OPCODE_HOOKI; + + if ((index & 0xffffff) != index) { + ctx->error = PORE_INLINE_UINT24_REQUIRED; + } else { + operand = index; + pore_inline_instruction3(ctx, opcode, operand, imm); + } + return ctx->error; +} + + +// Assemble BRA, BSR and LOOP +// +// The branch target here is a bytewise location counter. The target must be +// 4-byte aligned and must be within the legal signed 24-bit word offset of +// the current LC. Unaligned targets cause PORE_INLINE_ALIGNMENT_ERROR. +// Unreachable targets cause PORE_INLINE_UNREACHABLE_TARGET. + +int +pore_inline_bra(PoreInlineContext *ctx, int opcode, PoreInlineLocation target) +{ + int32_t offset; + uint32_t operand; + + if (target % 4) { + ctx->error = PORE_INLINE_ALIGNMENT_ERROR; + } else { + offset = (int32_t)(target - ctx->lc) / 4; + if ((offset >= (1 << 23)) || + (offset < -(1 << 23))) { + ctx->error = PORE_INLINE_UNREACHABLE_TARGET; + } else { + operand = offset & 0xffffff; + pore_inline_instruction1(ctx, opcode, operand); + } + } + return ctx->error; +} + + +// Assemble BRAZ and BRANZ +// +// The branch target here is a bytewise location counter. The target must be +// 4-byte aligned and must be within the legal signed 20-bit word offset of +// the current LC. Unaligned targets cause PORE_INLINE_ALIGNMENT_ERROR. +// Unreachable targets cause PORE_INLINE_UNREACHABLE_TARGET. Illegal +// operands cause PORE_INLINE_ILLEGAL_REGISTER. + +int +pore_inline_brac(PoreInlineContext *ctx, int opcode, int reg, + PoreInlineLocation target) +{ + int32_t offset; + uint32_t operand; + + if (target % 4) { + ctx->error = PORE_INLINE_ALIGNMENT_ERROR; + } else if (!pore_branch_compare_data(reg)) { + ctx->error = PORE_INLINE_ILLEGAL_REGISTER; + } else { + offset = (int32_t)(target - ctx->lc) / 4; + if ((offset >= (1 << 20)) || + (offset < -(1 << 20))) { + ctx->error = PORE_INLINE_UNREACHABLE_TARGET; + } else { + operand = (offset & 0xfffff) | (reg << 20); + pore_inline_instruction1(ctx, opcode, operand); + } + } + return ctx->error; +} + + +// Assemble CMPIBRAEQ, CMPIBRANE, CMPIBSREQ +// +// The branch target here is a bytewise location counter. The target must be +// 4-byte aligned and must be within the legal signed 24-bit word offset of +// the current LC. Unaligned targets cause PORE_INLINE_ALIGNMENT_ERROR. +// Unreachable targets cause PORE_INLINE_UNREACHABLE_TARGET. Illegal +// operands cause PORE_INLINE_ILLEGAL_REGISTER. + +int +pore_inline_cmpibra(PoreInlineContext *ctx, int opcode, int reg, + PoreInlineLocation target, uint64_t imm) +{ + int32_t offset; + uint32_t operand; + + if (target % 4) { + ctx->error = PORE_INLINE_ALIGNMENT_ERROR; + } else if (reg != D0) { + ctx->error = PORE_INLINE_ILLEGAL_REGISTER; + } else { + offset = (int32_t)(target - ctx->lc) / 4; + if ((offset >= (1 << 23)) || + (offset < -(1 << 23))) { + ctx->error = PORE_INLINE_UNREACHABLE_TARGET; + } else { + operand = offset & 0xffffff; + pore_inline_instruction3(ctx, opcode, operand, imm); + } + } + return ctx->error; +} + + +// Assemble BRAD and BSRD +// +// Illegal operands cause PORE_INLINE_ILLEGAL_REGISTER. + +int +pore_inline_brad(PoreInlineContext *ctx, int opcode, int reg) +{ + uint32_t operand; + + if (!pore_data(reg)) { + ctx->error = PORE_INLINE_ILLEGAL_REGISTER; + } else { + operand = reg << 20; + pore_inline_instruction1(ctx, opcode, operand); + } + return ctx->error; +} + + +// Assemble ANDI, ORI, XORI +// +// Source and destination must be of class 'data' otherwise the +// PORE_INLINE_ILLEGAL_REGISTER error is generated. + +int +pore_inline_ilogic(PoreInlineContext *ctx, int opcode, + int dest, int src, uint64_t imm) +{ + uint32_t operand; + + if (!pore_data(dest) || !pore_data(src)) { + ctx->error = PORE_INLINE_ILLEGAL_REGISTER; + } else { + operand = (dest << 20) | (src << 16); + pore_inline_instruction3(ctx, opcode, operand, imm); + } + return ctx->error; +} + + +// Assemble AND, OR, XOR, ADD, SUB +// +// Destination must be of class 'data' otherwise the +// PORE_INLINE_ILLEGAL_REGISTER error is generated. src1 and src2 must be D0, +// D1 respectively otherwise the PORE_INLINE_ILLEGAL_REGISTER error is +// generated. + +int +pore_inline_alurr(PoreInlineContext *ctx, + int opcode, int dest, int src1, int src2) +{ + uint32_t operand; + + if (!pore_data(dest) || (src1 != D0) || (src2 != D1)) { + ctx->error = PORE_INLINE_ILLEGAL_REGISTER; + } else { + operand = (dest << 20); + pore_inline_instruction1(ctx, opcode, operand); + } + return ctx->error; +} + + +// Assemble ADDS and SUBS +// +// Destination must be of class 'ls_destination' and must be equal to source, +// otherwise the PORE_INLINE_ILLEGAL_REGISTER error is generated. If the +// immediate is not a signed 16-bit immediate then the +// PORE_INLINE_INT16_REQUIRED error is generated. + +int +pore_inline_adds(PoreInlineContext *ctx, + int opcode, int dest, int src, int imm) +{ + uint32_t operand; + + if (!pore_ls_destination(dest) || (dest != src)) { + ctx->error = PORE_INLINE_ILLEGAL_REGISTER; + } else { + if ((imm >= (1 << 15)) || + (imm < -(1 << 15))) { + ctx->error = PORE_INLINE_INT16_REQUIRED; + } else { + operand = (dest << 20) | (imm & 0xffff); + pore_inline_instruction1(ctx, opcode, operand); + } + } + return ctx->error; +} + + +// Assemble NEG +// +// Source and destination must be of class 'data' otherwise the +// PORE_INLINE_ILLEGAL_REGISTER error is generated. + +int +pore_NEG(PoreInlineContext *ctx, int dest, int src) +{ + uint32_t operand; + int opcode = PGAS_OPCODE_NEG; + + if (!pore_data(dest) || !pore_data(src)) { + ctx->error = PORE_INLINE_ILLEGAL_REGISTER; + } else { + operand = (dest << 20) | (src << 16); + pore_inline_instruction1(ctx, opcode, operand); + } + return ctx->error; +} + + +// Assemble MR +// +// The source must be an 'mr_source' and the destination must be an +// 'mr_destination' otherwise the PORE_INLINE_ILLEGAL_REGISTER error is +// generated. + +int +pore_MR(PoreInlineContext *ctx, int dest, int src) +{ + uint32_t operand; + int opcode = PGAS_OPCODE_MR; + + if (!pore_mr_destination(dest) || !pore_mr_source(src)) { + ctx->error = PORE_INLINE_ILLEGAL_REGISTER; + } else { + operand = (dest << 20) | (src << 16); + pore_inline_instruction1(ctx, opcode, operand); + } + return ctx->error; +} + + + +// Assemble ROLS +// +// Source and destination must be of class 'data' otherwise the +// PORE_INLINE_ILLEGAL_REGISTER error is generated. Illegal shifts yield the +// PORE_INLINE_ILLEGAL_ROTATE error. + +int +pore_ROLS(PoreInlineContext *ctx, int dest, int src, int imm) +{ + uint32_t operand; + int opcode = PGAS_OPCODE_ROLS; + + if (!pore_data(dest) || !pore_data(src)) { + ctx->error = PORE_INLINE_ILLEGAL_REGISTER; + } else if ((imm != 1) && + (imm != 4) && + (imm != 8) && + (imm != 16) && + (imm != 32)) { + ctx->error = PORE_INLINE_ILLEGAL_ROTATE; + } else { + operand = (dest << 20) | (src << 16) | imm; + pore_inline_instruction1(ctx, opcode, operand); + } + return ctx->error; +} + + +// Assemble LS +// +// The destination must be an 'ls_destination' otherwise the +// PORE_INLINE_ILLEGAL_REGISTER error is generated. If the immediate is not +// a signed 20-bit immediate then the PORE_INLINE_INT20_REQUIRED error is +// generated. + +int +pore_LS(PoreInlineContext *ctx, int dest, int imm) +{ + uint32_t operand; + int opcode = PGAS_OPCODE_LS; + + if (!pore_ls_destination(dest)) { + ctx->error = PORE_INLINE_ILLEGAL_REGISTER; + } else if ((imm >= (1 << 19)) || + (imm < -(1 << 19))) { + ctx->error = PORE_INLINE_INT20_REQUIRED; + } else { + operand = (dest << 20) | (imm & 0xfffff); + pore_inline_instruction1(ctx, opcode, operand); + } + return ctx->error; +} + + +// Assemble LI +// +// The destination must be an 'li destination' otherwise the +// PORE_INLINE_ILLEGAL_REGISTER error is generated. + +int +pore_LI(PoreInlineContext *ctx, int dest, uint64_t imm) +{ + uint32_t operand; + int opcode = PGAS_OPCODE_LI; + + if (!pore_li_destination(dest)) { + ctx->error = PORE_INLINE_ILLEGAL_REGISTER; + } else { + operand = dest << 20; + pore_inline_instruction3(ctx, opcode, operand, imm); + } + return ctx->error; +} + + +// LD, LDANDI, STD, STI, BSI, BCI + +static void +pervasive_ima24(PoreInlineContext *ctx, + int opcode, uint32_t offset, int base, uint64_t imm) +{ + uint32_t operand; + + if ((offset & 0x80f00000) != 0) { + ctx->error = PORE_INLINE_ILLEGAL_SCOM_ADDRESS; + } else { + operand = ((base % 2) << 22) | (offset & 0xfffff); + switch (opcode) { + case PGAS_OPCODE_LD0: + case PGAS_OPCODE_LD1: + case PGAS_OPCODE_STD0: + case PGAS_OPCODE_STD1: + pore_inline_instruction1(ctx, opcode, operand); + break; + default: + pore_inline_instruction3(ctx, opcode, operand, imm); + break; + } + } +} + + +static void +memory_ima24(PoreInlineContext *ctx, + int opcode, uint32_t offset, int base, uint64_t imm) +{ + uint32_t operand; + + if ((offset & 0x3fffff) != offset) { + ctx->error = PORE_INLINE_UINT22_REQUIRED; + } else if ((offset % 8) != 0) { + ctx->error = PORE_INLINE_ALIGNMENT_ERROR; + } else { + operand = 0x800000 | ((base % 2) << 22) | (offset & 0x3fffff); + switch (opcode) { + case PGAS_OPCODE_LD0: + case PGAS_OPCODE_LD1: + case PGAS_OPCODE_STD0: + case PGAS_OPCODE_STD1: + pore_inline_instruction1(ctx, opcode, operand); + break; + default: + pore_inline_instruction3(ctx, opcode, operand, imm); + break; + } + } +} + + +static void +ima24(PoreInlineContext *ctx, + int opcode, uint32_t offset, int base, uint64_t imm) +{ + if (pore_pervasive_chiplet_id(base)) { + pervasive_ima24(ctx, opcode, offset, base, imm); + } else if (pore_address(base)) { + memory_ima24(ctx, opcode, offset, base, imm); + } else { + ctx->error = PORE_INLINE_ILLEGAL_REGISTER; + } +} + +#include <stdio.h> + +int +pore_inline_load_store(PoreInlineContext *ctx, + int opcode, int src_dest, int32_t offset, int base, + uint64_t imm) +{ + switch (opcode) { + + case PORE_INLINE_PSEUDO_LD: + case PORE_INLINE_PSEUDO_LDANDI: + case PORE_INLINE_PSEUDO_STD: + + // These three pick the real opcode based on the dest. register + + if (!pore_data(src_dest)) { + ctx->error = PORE_INLINE_ILLEGAL_REGISTER; + } else { + switch (opcode) { + case PORE_INLINE_PSEUDO_LD: + opcode = (src_dest == D0) ? + PGAS_OPCODE_LD0 : PGAS_OPCODE_LD1; + break; + case PORE_INLINE_PSEUDO_LDANDI: + opcode = (src_dest == D0) ? + PGAS_OPCODE_LD0ANDI : PGAS_OPCODE_LD1ANDI; + break; + case PORE_INLINE_PSEUDO_STD: + opcode = (src_dest == D0) ? + PGAS_OPCODE_STD0 : PGAS_OPCODE_STD1; + break; + } + } + break; + + case PGAS_OPCODE_BSI: + case PGAS_OPCODE_BCI: + + if (src_dest != D0) { + ctx->error = PORE_INLINE_ILLEGAL_REGISTER; + } + break; + + case PGAS_OPCODE_STI: + break; + + default: + ctx->error = PORE_INLINE_BUG; + } + + if (ctx->error == 0) { + ima24(ctx, opcode, offset, base, imm); + } + + return ctx->error; +} + + +// Assemble BRAIA + +int +pore_BRAIA(PoreInlineContext *ctx, + uint16_t address_space, uint32_t offset) +{ + int opcode = PGAS_OPCODE_BRAI; + uint32_t operand = 0; + uint64_t imm = ((uint64_t)address_space << 32) | offset; + + pore_inline_instruction3(ctx, opcode, operand, imm); + + return ctx->error; +} + + +// Assemble SCAND + +int +pore_SCAND(PoreInlineContext *ctx, + int update, int capture, uint16_t length, + uint32_t select, uint32_t offset) +{ + int opcode = PGAS_OPCODE_SCAND; + uint32_t operand; + uint64_t imm = ((uint64_t)select << 32) | offset; + + if ((update < 0) || + (update > 1) || + (capture < 0) || + (capture > 1)) { + ctx->error = PORE_INLINE_INVALID_PARAMETER; + } else { + opcode = PGAS_OPCODE_SCAND; + operand = (update << 23) | (capture << 22) | length; + pore_inline_instruction3(ctx, opcode, operand, imm); + } + return ctx->error; +} + + +/// Fix up a PORE inline assembler forward branch instruction +/// +/// \param ctx A pointer to the initialized PoreInlineContext object +/// controlling inline assembly. +/// +/// \param source The PORE inline location counter associated with the source +/// instruction of the forward branch. +/// +/// \param target The PORE inline location counter associated with the target +/// instruction of the forward branch. +/// +/// For usage examples, see the documentation \ref pore_inline_assembler. +/// Although intended for forward branches, this API could be used to create +/// backward branches as well. Note however the limitation that the \a source +/// must be in the current context, since the source instruction needs to be +/// reassembled with the branch target. In theory the \a target could be +/// anywhere, as long as the location counter of the target is known. +/// +/// \retval 0 Success +/// +/// \retval code Failure. Any non-zero return is the PORE inline assmebler +/// error code. The failure code is also stored in the PoreInlineContext +/// object \a error field. The most likely causes of failure include a source +/// location that is not in the current context or not associated with a +/// branch instruction. + +int +pore_inline_branch_fixup(PoreInlineContext *ctx, + PoreInlineLocation source, + PoreInlineLocation target) +{ + uint32_t instruction; + int32_t distance; + uint64_t imm; + int opcode, reg; + PoreInlineContext source_ctx; + + if ((source < ctx->original_lc) || + (source > ctx->lc)) { + ctx->error = PORE_INLINE_ILLEGAL_SOURCE_LC; + } else { + + // Create a context as it existed when the source instruction was + // initially assembled, and then reassemble the instruction in that + // context with the actual target. + + distance = ctx->lc - source; + + source_ctx = *ctx; + source_ctx.lc = source; + source_ctx.remaining += distance; + source_ctx.lc_address -= distance; + source_ctx.error = 0; + + instruction = pore_inline_host32(source_ctx.lc_address); + opcode = (instruction >> 25); + reg = (instruction >> 20) & 0xf; + + switch (opcode) { + case PGAS_OPCODE_BRA: + pore_BRA(&source_ctx, target); + break; + case PGAS_OPCODE_BSR: + pore_BSR(&source_ctx, target); + break; + case PGAS_OPCODE_LOOP: + pore_LOOP(&source_ctx, target); + break; + case PGAS_OPCODE_BRAZ: + pore_BRAZ(&source_ctx, reg, target); + break; + case PGAS_OPCODE_BRANZ: + pore_BRANZ(&source_ctx, reg, target); + break; + case PGAS_OPCODE_CMPIBRAEQ: + imm = pore_inline_host64(source_ctx.lc_address + 4); + pore_CMPIBRAEQ(&source_ctx, D0, target, imm); + break; + case PGAS_OPCODE_CMPIBRANE: + imm = pore_inline_host64(source_ctx.lc_address + 4); + pore_CMPIBRANE(&source_ctx, D0, target, imm); + break; + case PGAS_OPCODE_CMPIBSREQ: + imm = pore_inline_host64(source_ctx.lc_address + 4); + pore_CMPIBSREQ(&source_ctx, D0, target, imm); + break; + default: + source_ctx.error = PORE_INLINE_NOT_A_BRANCH; + break; + } + + ctx->error = source_ctx.error; + } + return ctx->error; +} diff --git a/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/proc_slw_build.C b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/proc_slw_build.C new file mode 100644 index 000000000..3744f1fea --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/proc_slw_build.C @@ -0,0 +1,419 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/proc_slw_build.C $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +/*------------------------------------------------------------------------------*/ +/* *! TITLE : proc_slw_build */ +/* *! DESCRIPTION : Extracts and decompresses delta ring states from EPROM */ +// image. Utilizes the linked list approach (LLA) to extract +// and position wiggle-flip programs in .rings according to +// back pointer, DD level, phase and override settings. +/* *! OWNER NAME : Michael Olsen cmolsen@us.ibm.com */ +// +/* *! EXTENDED DESCRIPTION : */ +// +/* *! USAGE : To build (for Hostboot) - */ +// buildfapiprcd -r ver-12-5 -C "p8_image_help.C,p8_scan_compression.C" -c "sbe_xip_image.c,pore_inline_assembler.c,pore_inline_disassembler.c,p8_pore_static_data.c" -e "../../xml/error_info/proc_slw_build_errors.xml" proc_slw_build.C +// Parameter list - +// See function definition below. +// Alternative usages - +// To build for scanning by EPM team: +// buildfapiprcd_cmo -u "SLW_BUILD_WF_P0_FIX,SLW_BUILD_SYSPHASE_ZERO_MODE,SLW_COMMAND_LINE" -r ... +// +/* *! ASSUMPTIONS : */ +// - For proc_slw_build, sysPhase=1 is assumed during real hostboot. +// +/* *! COMMENTS : */ +// - All image content, incl .initf content and ring layout, is handled +// in BE format. No matter which platform. +// - A ring may only be requested with the sysPhase=0 or 1. Any other +// sysPhase value, incl sysPhase=2, will cause no rings to be found. +// +/*------------------------------------------------------------------------------*/ + +#include "proc_slw_build.H" + +extern "C" { + +using namespace fapi; + +// Parameter list: +// fapi::Target &i_target: Hardware target +// void *i_imageIn: Pointer to memory mapped input SBE-XIP EPROM image +// uint32_t i_sizeImageIn: Size of input image. +// void *i_imageOut: Pointer to where to put SLW mainstore image +// uint32_t *io_sizeImageOut: Size of output image. Initial upper limit supplied by HB. Final size returned. +// +ReturnCode proc_slw_build( const fapi::Target &i_target, + const void *i_imageIn, + uint32_t i_sizeImageIn, + void *i_imageOut, + uint32_t *io_sizeImageOut) +{ + ReturnCode rc; + uint8_t l_uint8 = 0; + uint32_t ddLevel=0; +#ifdef SLW_BUILD_SYSPHASE_ZERO_MODE + uint8_t sysPhase=0; +#else + uint8_t sysPhase=1; +#endif + + uint32_t rcLoc=0, rcSearch=0, i, countWF=0; + uint32_t sizeImage=0, sizeImageOutMax, sizeImageTmp, sizeImageOld; + uint8_t *deltaRingDxed=NULL; + CompressedScanData *deltaRingRS4=NULL; + DeltaRingLayout rs4RingLayout; + void *nextRing=NULL; + + uint32_t ringBitLen=0, ringByteLen=0, ringTrailBits=0; + + uint32_t *wfInline=NULL; + uint32_t wfInlineLenInWords; + + sizeImageOutMax = *io_sizeImageOut; + + if (sizeImageOutMax<i_sizeImageIn) { + FAPI_ERR("Inp image size (from caller): %i",i_sizeImageIn); + FAPI_ERR("Max image size (from caller): %i",*io_sizeImageOut); + uint32_t & DATA_IMG_SIZE_INP = i_sizeImageIn; + uint32_t & DATA_IMG_SIZE_MAX = *io_sizeImageOut; + FAPI_SET_HWP_ERROR(rc, RC_PROC_SLWB_INPUT_IMAGE_SIZE_MESS); + return rc; + } + + + // ========================================================================== + // Check and copy image to mainstore and clean it up. + // ========================================================================== + // ToDo: + // - Eventually, automate emptying sections in proper order (last section goes first). + // - For 5/15, assume following order of removal: rings, pibmem0, and halt. + // + // First, check supplied size and validation of input EPROM image. + // + sbe_xip_image_size((void*)i_imageIn, &sizeImage); + rcLoc = sbe_xip_validate((void*)i_imageIn, sizeImage); + if (rcLoc) { + FAPI_ERR("xip_validate() failed w/rcLoc=%i",rcLoc); + uint32_t & RC_LOCAL = rcLoc; + FAPI_SET_HWP_ERROR(rc, RC_PROC_SLWB_INTERNAL_IMAGE_ERR); + return rc; + } + if (sizeImage!=i_sizeImageIn) { + FAPI_ERR("Size obtained from image's header (=%i) differs from supplied size (=%i).", + sizeImage,i_sizeImageIn); + uint32_t & DATA_IMG_SIZE_INP = i_sizeImageIn; + uint32_t & DATA_IMG_SIZE = sizeImage; + FAPI_SET_HWP_ERROR(rc, RC_PROC_SLWB_IMAGE_SIZE_MISMATCH); + return rc; + } + FAPI_DBG("Image size (in EPROM): %i",i_sizeImageIn); + + // Second, copy input image to supplied mainstore location. + // + memcpy( i_imageOut, i_imageIn, i_sizeImageIn); + sbe_xip_image_size(i_imageOut, &sizeImage); + rcLoc = sbe_xip_validate(i_imageOut, sizeImage); + if (rcLoc) { + FAPI_ERR("xip_validate() failed w/rcLoc=%i",rcLoc); + uint32_t & RC_LOCAL=rcLoc; + FAPI_SET_HWP_ERROR(rc, RC_PROC_SLWB_MS_INTERNAL_IMAGE_ERR); + return rc; + } + if (sizeImage!=i_sizeImageIn) { + FAPI_ERR("Size obtained from image's header (=%i) differs from supplied size (=%i).", + sizeImage,i_sizeImageIn); + uint32_t & DATA_IMG_SIZE_INP = i_sizeImageIn; + uint32_t & DATA_IMG_SIZE = sizeImage; + FAPI_SET_HWP_ERROR(rc, RC_PROC_SLWB_MS_IMAGE_SIZE_MISMATCH); + return rc; + } + + // Third, delete .rings and .pibmem0 sections (but keep .halt) + // + rcLoc = sbe_xip_delete_section( i_imageOut, SBE_XIP_SECTION_RINGS); + if (rcLoc) { + FAPI_ERR("xip_delete_section(.rings) failed w/rcLoc=%i",rcLoc); + uint32_t & RC_LOCAL=rcLoc; + FAPI_SET_HWP_ERROR(rc, RC_PROC_SLWB_DELETE_IMAGE_SECTION_ERROR); + return rc; + } + sbe_xip_image_size(i_imageOut, &sizeImage); + rcLoc = sbe_xip_validate(i_imageOut, sizeImage); + if (rcLoc) { + FAPI_ERR("xip_validate() failed w/rcLoc=%i",rcLoc); + uint32_t & RC_LOCAL=rcLoc; + FAPI_SET_HWP_ERROR(rc, RC_PROC_SLWB_MS_INTERNAL_IMAGE_ERR); + return rc; + } + FAPI_DBG("Image size (after .rings delete): %i",sizeImage); + + rcLoc = sbe_xip_delete_section( i_imageOut, SBE_XIP_SECTION_PIBMEM0); + if (rcLoc) { + FAPI_ERR("xip_delete_section(.pibmem0) failed w/rcLoc=%i",rcLoc); + uint32_t & RC_LOCAL=rcLoc; + FAPI_SET_HWP_ERROR(rc, RC_PROC_SLWB_DELETE_IMAGE_SECTION_ERROR); + return rc; + } + sbe_xip_image_size(i_imageOut, &sizeImage); + rcLoc = sbe_xip_validate(i_imageOut, sizeImage); + if (rcLoc) { + FAPI_ERR("xip_validate() failed w/rcLoc=%i",rcLoc); + uint32_t & RC_LOCAL=rcLoc; + FAPI_SET_HWP_ERROR(rc, RC_PROC_SLWB_MS_INTERNAL_IMAGE_ERR); + return rc; + } + FAPI_DBG("Image size (after .pibmem0 delete): %i",sizeImage); + + // ========================================================================== + // Get DD level from FAPI attributes. + // ========================================================================== + // $$rc = FAPI_ATTR_GET(ATTR_EC, &i_target, l_uint8); + rc = FAPI_ATTR_GET_PRIVILEGED(ATTR_EC, &i_target, l_uint8); + ddLevel = (uint32_t)l_uint8; + if (rc) { + FAPI_ERR("FAPI_ATTR_GET() failed w/rc=%i and ddLevel=0x%02x",(uint32_t)rc,l_uint8); + return rc; + } + + /*************************************************************************** + * SEARCH LOOP - Begin * + ***************************************************************************/ + do { + + FAPI_DBG("nextRing (at top)=0x%016llx",(uint64_t)nextRing); + + + // ========================================================================== + // Get ring layout from image + // ========================================================================== + FAPI_DBG("--> Reading RS4 delta ring info from SBE-XIP Image."); + rcLoc = get_ring_layout_from_image( i_imageIn, + ddLevel, + sysPhase, + &rs4RingLayout, + &nextRing); + rcSearch = rcLoc; + if (rcSearch!=DSLWB_RING_SEARCH_MATCH && + rcSearch!=DSLWB_RING_SEARCH_EXHAUST_MATCH && + rcSearch!=DSLWB_RING_SEARCH_NO_MATCH) { + FAPI_ERR("\tERROR : Getting delta ring from image was unsuccessful (rcSearch=%i).",rcSearch); + FAPI_ERR("\tNo wiggle-flip programs will be stored in .rings section."); + FAPI_ERR("\tThe following ELF sections have been emptied: .rings, .pibmem0, .ipl_text."); + uint32_t & RC_LOCAL=rcLoc; + FAPI_SET_HWP_ERROR(rc, RC_PROC_SLWB_RING_RETRIEVAL_ERROR); + return rc; + } + if (rcSearch==DSLWB_RING_SEARCH_MATCH || + rcSearch==DSLWB_RING_SEARCH_EXHAUST_MATCH) + FAPI_DBG("\tRetrieving RS4 delta ring was successful."); + + // Check if we're done at this point. + // + if (rcSearch==DSLWB_RING_SEARCH_NO_MATCH) { + FAPI_INF("Wiggle-flip programming done."); + FAPI_INF("Number of wf programs appended: %i", countWF); + if (countWF==0) + FAPI_INF("ZERO WF programs appended to .rings section."); + sizeImageTmp = sizeImageOutMax; + rcLoc = append_empty_section( i_imageOut, + &sizeImageTmp, + SBE_XIP_SECTION_SLW, + SLW_SLW_SECTION_SIZE); + if (rcLoc) { + if (rcLoc==IMGBUILD_ERR_IMAGE_TOO_LARGE) { + uint32_t & DATA_IMG_SIZE_OLD=sizeImageOld; + uint32_t & DATA_IMG_SIZE_EST=sizeImageTmp; + uint32_t & DATA_IMG_SIZE_MAX=sizeImageOutMax; + FAPI_SET_HWP_ERROR(rc, RC_PROC_SLWB_MAX_IMAGE_SIZE_EXCEEDED); + } + else { + uint32_t & RC_LOCAL=rcLoc; + FAPI_SET_HWP_ERROR(rc, RC_PROC_SLWB_APPEND_SLW_SECTION_ERROR); + } + return rc; + } + FAPI_INF("SLW section allocated for Ramming table."); + sbe_xip_image_size( i_imageOut, io_sizeImageOut); + FAPI_INF("Final SLW image size: %i", *io_sizeImageOut); + return FAPI_RC_SUCCESS; + } + + deltaRingRS4 = (CompressedScanData*)rs4RingLayout.rs4Delta; + + FAPI_DBG("Dumping ring layout:"); + FAPI_DBG("\tentryOffset = %i",(uint32_t)myRev64(rs4RingLayout.entryOffset)); + FAPI_DBG("\tbackItemPtr = 0x%016llx",myRev64(rs4RingLayout.backItemPtr)); + FAPI_DBG("\tsizeOfThis = %i",myRev32(rs4RingLayout.sizeOfThis)); + FAPI_DBG("\tsizeOfMeta = %i",myRev32(rs4RingLayout.sizeOfMeta)); + FAPI_DBG("\tddLevel = %i",myRev32(rs4RingLayout.ddLevel)); + FAPI_DBG("\tsysPhase = %i",rs4RingLayout.sysPhase); + FAPI_DBG("\toverride = %i",rs4RingLayout.override); + FAPI_DBG("\treserved1+2 = %i",rs4RingLayout.reserved1|rs4RingLayout.reserved2); + FAPI_DBG("\tRS4 magic # = 0x%08x",myRev32(deltaRingRS4->iv_magic)); + FAPI_DBG("\tRS4 total size = %i",myRev32(deltaRingRS4->iv_size)); + FAPI_DBG("\tUnXed data size = %i",myRev32(deltaRingRS4->iv_length)); + FAPI_DBG("\tScan select = 0x%08x",myRev32(deltaRingRS4->iv_scanSelect)); + FAPI_DBG("\tHeader version = 0x%02x",deltaRingRS4->iv_headerVersion); + FAPI_DBG("\tFlush optimize = 0x%02x (reverse of override)",deltaRingRS4->iv_flushOptimization); + FAPI_DBG("\tReserved = 0x%02x",deltaRingRS4->iv_reserved); + FAPI_DBG("\tChiplet ID = 0x%02x",deltaRingRS4->iv_chipletId); + FAPI_DBG("Dumping meta data:"); + FAPI_DBG("\tsizeOfData = %i",myRev32(rs4RingLayout.sizeOfMeta)); + FAPI_DBG("\tMeta data = "); + for (i=0; i<myRev32(rs4RingLayout.sizeOfMeta); i++) { // String may not be null terminated. + FAPI_DBG("%c",rs4RingLayout.metaData[i]); + } + + + // ========================================================================== + // Decompress RS4 delta state. + // ========================================================================== + FAPI_DBG("--> Decompressing RS4 delta ring."); + // Note: deltaRingDxed is left-aligned. If converting to uint32_t, do BE->LE flip. + deltaRingDxed = NULL; + rcLoc = rs4_decompress( &deltaRingDxed, + &ringBitLen, + deltaRingRS4); + if (rcLoc) { + FAPI_ERR("\tERROR : rs4_decompress() failed: rc=%i",rcLoc); + if (deltaRingDxed) free(deltaRingDxed); + uint32_t & RC_LOCAL=rcLoc; + FAPI_SET_HWP_ERROR(rc, RC_PROC_SLWB_RS4_DECOMPRESSION_ERROR); + return rc; + } + FAPI_DBG("\tDecompression successful.\n"); + + ringByteLen = (ringBitLen-1)/8+1; + ringTrailBits = ringBitLen - 8*(ringByteLen-1); + + + // ========================================================================== + // Create Wiggle-Flip Programs + // ========================================================================== + FAPI_DBG("--> Creating Wiggle-Flip Program."); + rcLoc = create_wiggle_flip_prg( (uint32_t*)deltaRingDxed, + ringBitLen, + myRev32(deltaRingRS4->iv_scanSelect), + (uint32_t)deltaRingRS4->iv_chipletId, + &wfInline, + &wfInlineLenInWords); + if (rcLoc) { + FAPI_ERR("ERROR : create_wiggle_flip_prg() failed w/rcLoc=%i",rcLoc); + if (deltaRingDxed) free(deltaRingDxed); + if (wfInline) free(wfInline); + uint32_t & RC_LOCAL=rcLoc; + FAPI_SET_HWP_ERROR(rc, RC_PROC_SLWB_WF_CREATION_ERROR); + return rc; + } + FAPI_DBG("\tWiggle-flip programming successful."); + + + // ========================================================================== + // Append Wiggle-Flip programs to .rings section. + // ========================================================================== + FAPI_DBG("--> Appending wiggle-flip and layout header to .rings section."); + sizeImageTmp = sizeImageOutMax; + rcLoc = write_wiggle_flip_to_image( i_imageOut, + &sizeImageTmp, + &rs4RingLayout, + wfInline, + wfInlineLenInWords); + if (rcLoc) { + FAPI_ERR("ERROR : write_wiggle_flip_to_image() failed w/rcLoc=%i",rcLoc); + if (deltaRingDxed) free(deltaRingDxed); + if (wfInline) free(wfInline); + if (rcLoc==IMGBUILD_ERR_IMAGE_TOO_LARGE) { + uint32_t & DATA_IMG_SIZE_OLD=sizeImageOld; + uint32_t & DATA_IMG_SIZE_EST=sizeImageTmp; + uint32_t & DATA_IMG_SIZE_MAX=sizeImageOutMax; + FAPI_SET_HWP_ERROR(rc, RC_PROC_SLWB_MAX_IMAGE_SIZE_EXCEEDED); + } + else { + uint32_t & RC_LOCAL=rcLoc; + FAPI_SET_HWP_ERROR(rc, RC_PROC_SLWB_IMAGE_UPDATE_ERROR); + } + return rc; + } + FAPI_DBG("\tUpdating image w/wiggle-flip program + header was successful."); + + // Update some variables for debugging and error reporting. + sizeImageOld = sizeImageTmp; + countWF++; + + + // ========================================================================== + // Clean up + // ========================================================================== + if (deltaRingDxed) free(deltaRingDxed); + if (wfInline) free(wfInline); + + + // ========================================================================== + // Are we done? + // ========================================================================== + if (rcSearch==DSLWB_RING_SEARCH_EXHAUST_MATCH) { + FAPI_INF("Wiggle-flip programming done."); + FAPI_INF("Number of wf programs appended: %i", countWF); + if (countWF==0) + FAPI_INF("ZERO WF programs appended to .rings section."); + sizeImageTmp = sizeImageOutMax; + rcLoc = append_empty_section( i_imageOut, + &sizeImageTmp, + SBE_XIP_SECTION_SLW, + SLW_SLW_SECTION_SIZE); + if (rcLoc) { + if (rcLoc==IMGBUILD_ERR_IMAGE_TOO_LARGE) { + uint32_t & DATA_IMG_SIZE_OLD=sizeImageOld; + uint32_t & DATA_IMG_SIZE_EST=sizeImageTmp; + uint32_t & DATA_IMG_SIZE_MAX=sizeImageOutMax; + FAPI_SET_HWP_ERROR(rc, RC_PROC_SLWB_MAX_IMAGE_SIZE_EXCEEDED); + } + else { + uint32_t & RC_LOCAL=rcLoc; + FAPI_SET_HWP_ERROR(rc, RC_PROC_SLWB_APPEND_SLW_SECTION_ERROR); + } + return rc; + } + FAPI_INF("SLW section allocated for Ramming table."); + sbe_xip_image_size( i_imageOut, io_sizeImageOut); + FAPI_INF("Final SLW image size: %i", *io_sizeImageOut); + return FAPI_RC_SUCCESS; + } + + FAPI_DBG("nextRing (at bottom)=0x%016llx",(uint64_t)nextRing); + + } while (nextRing!=NULL); + /*************************************************************************** + * SEARCH LOOP - End * + ***************************************************************************/ + + FAPI_ERR("ERROR : Shouldn't be in this code section. Check code."); + rcLoc = IMGBUILD_ERR_CHECK_CODE; + uint32_t & RC_LOCAL=rcLoc; + FAPI_SET_HWP_ERROR(rc, RC_PROC_SLWB_UNKOWN_ERROR); + return rc; + +} + +} // End of extern C diff --git a/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/proc_slw_build.H b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/proc_slw_build.H new file mode 100644 index 000000000..7db527191 --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/proc_slw_build.H @@ -0,0 +1,52 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/proc_slw_build.H $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ + +#include <fapi.H> +#include "p8_delta_scan_rw.h" +#include "p8_pore_table_gen_api.H" + +typedef fapi::ReturnCode (*proc_slw_build_FP_t) ( const fapi::Target&, + const void*, + uint32_t, + void*, + uint32_t*); + +extern "C" +{ + // Description: FAPI HWP entry point. proc_slw_build() constructs the + // Sleep-Winkle (SLW) image in mainstore during Hostboot + // IPL. + // Parameters: i_target: Processor chip target. + // *i_imageIn: Pointer to location of input SBE-XIP image. + // i_sizeImageIn: Size of input image. + // *i_imageOut: Pointer to location of output SLW image in + // mainstore. + // *io_sizeImageOut: On input, upper limit of size of output + // image. On output, final size of output image. + fapi::ReturnCode proc_slw_build( const fapi::Target &i_target, + const void *i_imageIn, + uint32_t i_sizeImageIn, + void *i_imageOut, + uint32_t *io_sizeImageOut); +} diff --git a/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/proc_slw_build_errors.xml b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/proc_slw_build_errors.xml new file mode 100644 index 000000000..e579245df --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/proc_slw_build_errors.xml @@ -0,0 +1,108 @@ +<!-- IBM_PROLOG_BEGIN_TAG + This is an automatically generated prolog. + + $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/proc_slw_build_errors.xml $ + + IBM CONFIDENTIAL + + COPYRIGHT International Business Machines Corp. 2012 + + p1 + + Object Code Only (OCO) source materials + Licensed Internal Code Source Materials + IBM HostBoot Licensed Internal Code + + The source code for this program is not published or other- + wise divested of its trade secrets, irrespective of what has + been deposited with the U.S. Copyright Office. + + Origin: 30 + + IBM_PROLOG_END_TAG --> +<!-- Error definitions for proc_slw_build procedure --> +<hwpErrors> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROC_SLWB_INPUT_IMAGE_SIZE_MESS</rc> + <description>Supplied max image size is too small or image too large.</description> + <ffdc>DATA_IMG_SIZE_INP</ffdc> + <ffdc>DATA_IMG_SIZE_MAX</ffdc> +</hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROC_SLWB_IMAGE_SIZE_MISMATCH</rc> + <description>Supplied image size differs from size in image header.</description> + <ffdc>DATA_IMG_SIZE_INP</ffdc> + <ffdc>DATA_IMG_SIZE</ffdc> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROC_SLWB_MS_IMAGE_SIZE_MISMATCH</rc> + <description>Supplied image size differs from size in mainstore image header.</description> + <ffdc>DATA_IMG_SIZE_INP</ffdc> + <ffdc>DATA_IMG_SIZE</ffdc> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROC_SLWB_MAX_IMAGE_SIZE_EXCEEDED</rc> + <description>Estimated image size exceeds max allowed size.</description> + <ffdc>DATA_IMG_SIZE_OLD</ffdc> + <ffdc>DATA_IMG_SIZE_EST</ffdc> + <ffdc>DATA_IMG_SIZE_MAX</ffdc> +</hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROC_SLWB_INTERNAL_IMAGE_ERR</rc> + <description>Unable to obtain either image size or to validate image.</description> + <ffdc>RC_LOCAL</ffdc> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROC_SLWB_MS_INTERNAL_IMAGE_ERR</rc> + <description>Unable to obtain either image size or to validate image in mainstore.</description> + <ffdc>RC_LOCAL</ffdc> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROC_SLWB_DELETE_IMAGE_SECTION_ERROR</rc> + <description>Error associated with deleting an image section.</description> + <ffdc>RC_LOCAL</ffdc> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROC_SLWB_RING_RETRIEVAL_ERROR</rc> + <description>Error associated with retrieving RS4 ring from image.</description> + <ffdc>RC_LOCAL</ffdc> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROC_SLWB_RS4_DECOMPRESSION_ERROR</rc> + <description>RS4 decompression failed.</description> + <ffdc>RC_LOCAL</ffdc> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROC_SLWB_WF_CREATION_ERROR</rc> + <description>Wiggle-flip programming failed.</description> + <ffdc>RC_LOCAL</ffdc> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROC_SLWB_IMAGE_UPDATE_ERROR</rc> + <description>Error associated with updating mainstore image.</description> + <ffdc>RC_LOCAL</ffdc> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROC_SLWB_APPEND_SLW_SECTION_ERROR</rc> + <description>Error associated with adding empty SLW section for ramming table.</description> + <ffdc>RC_LOCAL</ffdc> + </hwpError> + <!-- *********************************************************************** --> + <hwpError> + <rc>RC_PROC_SLWB_UNKOWN_ERROR</rc> + <description>Unknown error, shouldn't be in this code section.</description> + <ffdc>RC_LOCAL</ffdc> + </hwpError> +</hwpErrors> diff --git a/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/sbe_xip_image.c b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/sbe_xip_image.c new file mode 100644 index 000000000..722e8fdb7 --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/sbe_xip_image.c @@ -0,0 +1,2008 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/sbe_xip_image.c $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +// $Id: sbe_xip_image.c,v 1.17 2012/05/22 22:59:05 bcbrock Exp $ +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ipl/sbe/sbe_xip_image.c,v $ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2011 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- +// *! OWNER NAME: Bishop Brock Email: bcbrock@us.ibm.com +//------------------------------------------------------------------------------ + +/// \file sbe_xip_image.c +/// \brief APIs for validating, normalizing, searching and manipulating +/// SBE-XIP images. +/// +/// The background, APIs and implementation details are documented in the +/// document "SBE-XIP Binary format" currently available at this link: +/// +/// - https://mcdoc.boeblingen.de.ibm.com/out/out.ViewDocument.php?documentid=2678 +/// +/// \bug The sbe_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 <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include "sbe_xip_image.h" + + +//////////////////////////////////////////////////////////////////////////// +// Local Functions +//////////////////////////////////////////////////////////////////////////// + +#ifdef DEBUG_SBE_XIP_IMAGE + +// Debugging support, normally disabled. All of the formatted I/O you see in +// the code is effectively under this switch. + +#ifdef __FAPI + +#include "fapi.H" +#define fprintf(stream, ...) FAPI_ERR(__VA_ARGS__) +#define printf(...) FAPI_INF(__VA_ARGS__) +#define TRACE_NEWLINE "" + +#else // __FAPI + +#include <stdio.h> +#define TRACE_NEWLINE "\n" + +#endif // __FAPI + +// Portable formatting of uint64_t. The ISO C99 standard requires +// __STDC_FORMAT_MACROS to be defined in order for PRIx64 etc. to be defined. + +#define __STDC_FORMAT_MACROS +#include <inttypes.h> + +#define F0x016llx "0x%016" PRIx64 +#define F0x012llx "0x%012" PRIx64 + +static SBE_XIP_ERROR_STRINGS(sbe_xip_error_strings); + +#define TRACE_ERROR(x) \ + ({ \ + fprintf(stderr, "%s:%d : Returning error code %d : %s" TRACE_NEWLINE, \ + __FILE__, __LINE__, (x), \ + SBE_XIP_ERROR_STRING(sbe_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 + +static uint32_t revle32(const uint32_t i_x); + +static SBE_XIP_TYPE_STRINGS(type_strings); + +static void +dumpToc(int index, SbeXipToc* 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, + revle32(toc->iv_id), + revle32(toc->iv_data), + SBE_XIP_TYPE_STRING(type_strings, toc->iv_type), + toc->iv_section, + toc->iv_elements); +} + +#endif + +#if 0 + +static void +dumpItem(SbeXipItem* item) +{ + printf("SbeXipItem @ %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, + SBE_XIP_TYPE_STRING(type_strings, item->iv_type), + item->iv_elements); + dumpToc(-1, item->iv_toc); +} + +#endif /* 0 */ + +static void +dumpSectionTable(const void* i_image) +{ + int i, rc; + SbeXipSection section; + + printf("Section table dump of image @ %p\n" + " Entry Offset Size\n" + "-------------------------------\n", + i_image); + + for (i = 0; i < SBE_XIP_SECTIONS; i++) { + rc = sbe_xip_get_section(i_image, i, §ion); + if (rc) { + printf(">>> dumpSectionTable got error at entry %d : %s\n", + i, SBE_XIP_ERROR_STRING(sbe_xip_error_strings, rc)); + break; + } + printf("%7d 0x%08x 0x%08x\n", + i, section.iv_offset, section.iv_size); + } +} + +#else + +#define TRACE_ERROR(x) (x) +#define TRACE_ERRORX(x, ...) (x) +#define dumpToc(...) +#define dumpItem(...) +#define dumpSectionTable(...) + +#endif + + +// Note: For maximum flexibility we provide private versions of +// endian-conversion routines rather than counting on a system-specific header +// to provide these. + +/// Byte-reverse a 32-bit integer if on a little-endian machine + +static uint32_t +revle32(const uint32_t i_x) +{ + uint32_t rx; + +#ifndef _BIG_ENDIAN + uint8_t *pix = (uint8_t*)(&i_x); + uint8_t *prx = (uint8_t*)(&rx); + + prx[0] = pix[3]; + prx[1] = pix[2]; + prx[2] = pix[1]; + prx[3] = pix[0]; +#else + rx = i_x; +#endif + + return rx; +} + + +/// Byte-reverse a 64-bit integer if on a little-endian machine + +static uint64_t +revle64(const uint64_t i_x) +{ + uint64_t rx; + +#ifndef _BIG_ENDIAN + uint8_t *pix = (uint8_t*)(&i_x); + uint8_t *prx = (uint8_t*)(&rx); + + prx[0] = pix[7]; + prx[1] = pix[6]; + prx[2] = pix[5]; + prx[3] = pix[4]; + prx[4] = pix[3]; + prx[5] = pix[2]; + prx[6] = pix[1]; + prx[7] = pix[0]; +#else + rx = i_x; +#endif + + return rx; +} + + +/// What is the image link address? + +static uint64_t +linkAddress(const void* i_image) +{ + return revle64(((SbeXipHeader*)i_image)->iv_linkAddress); +} + + +/// What is the image size? + +static uint32_t +imageSize(const void* i_image) +{ + return revle32(((SbeXipHeader*)i_image)->iv_imageSize); +} + + +/// Set the image size + +static void +setImageSize(void* io_image, const size_t i_size) +{ + ((SbeXipHeader*)io_image)->iv_imageSize = revle32(i_size); +} + + +/// Re-establish the required final alignment + +static void +finalAlignment(void* io_image) +{ + uint32_t size; + + size = imageSize(io_image); + + if ((size % SBE_XIP_FINAL_ALIGNMENT) != 0) { + setImageSize(io_image, + size + (SBE_XIP_FINAL_ALIGNMENT - + (size % SBE_XIP_FINAL_ALIGNMENT))); + } +} + + +/// Compute a host address from an image address and offset + +static void* +hostAddressFromOffset(const void* i_image, const uint32_t offset) +{ + return (void*)((unsigned long)i_image + offset); +} + + +/// Convert a PORE address to a host address + +static void* +pore2Host(const void* i_image, const uint64_t i_poreAddress) +{ + return hostAddressFromOffset(i_image, + i_poreAddress - linkAddress(i_image)); +} + + +static int +validatePoreAddress(const void* i_image, + const uint64_t i_poreAddress, + const uint32_t size) +{ + int rc; + + if ((i_poreAddress < linkAddress(i_image)) || + (i_poreAddress > (linkAddress(i_image) + imageSize(i_image) - size))) { + rc = TRACE_ERRORX(SBE_XIP_INVALID_ARGUMENT, + "The PORE address " F0x012llx " is outside the bounds " + "of the image (" F0x012llx ":" F0x012llx ") for %u-byte access.\n", + i_poreAddress, + linkAddress(i_image), + linkAddress(i_image) + imageSize(i_image) - 1, + size); + } else { + rc = 0; + } + return rc; +} + + +/// Get the magic number from the image + +static uint64_t +magic(const void* i_image) +{ + return revle64(((SbeXipHeader*)i_image)->iv_magic); +} + + +/// Get the header version from the image + +static uint8_t +headerVersion(const void* i_image) +{ + return ((SbeXipHeader*)i_image)->iv_headerVersion; +} + + +/// Has the image been normalized? + +static uint8_t +normalized(const void* i_image) +{ + return ((SbeXipHeader*)i_image)->iv_normalized; +} + + +/// Has the image TOC been sorted? + +static uint8_t +sorted(const void* i_image) +{ + return ((SbeXipHeader*)i_image)->iv_tocSorted; +} + + +/// A quick check that the image exists, has the correct magic and header +/// version, and optionally is normalized. + +static int +quickCheck(const void* i_image, const int i_normalizationRequired) +{ + int rc; + + do { + rc = 0; + + if (i_image == 0) { + rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR, + "Image pointer is NULL (0)\n"); + break; + } + if ((magic(i_image) >> 32) != SBE_XIP_MAGIC) { + rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR, + "Magic number mismatch; Found " + "" F0x016llx ", expected 0x%08x........\n", + magic(i_image), SBE_XIP_MAGIC); + break; + } + if ((headerVersion(i_image)) != SBE_XIP_HEADER_VERSION) { + rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR, + "Header version mismatch; Expecting %d, " + "found %d\n", + SBE_XIP_HEADER_VERSION, headerVersion(i_image)); + break; + } + if (i_normalizationRequired && !normalized(i_image)) { + rc = TRACE_ERRORX(SBE_XIP_NOT_NORMALIZED, + "Image not normalized\n"); + break; + } + } while(0); + + return rc; +} + + +/// Convert a 32-bit relocatable offset to a full PORE 48-bit address + +static uint64_t +fullAddress(const void* i_image, uint32_t offset) +{ + return (linkAddress(i_image) & 0x0000ffff00000000ull) + offset; +} + + +/// Translate a section table entry + +static void +translateSection(SbeXipSection* o_dest, const SbeXipSection* i_src) +{ +#ifndef _BIG_ENDIAN + +#if SBE_XIP_HEADER_VERSION != 7 +#error This code assumes the SBE-XIP header version 7 layout +#endif + + o_dest->iv_offset = revle32(i_src->iv_offset); + o_dest->iv_size = revle32(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 + +static void +translateToc(SbeXipToc* o_dest, SbeXipToc* i_src) +{ +#ifndef _BIG_ENDIAN + +#if SBE_XIP_HEADER_VERSION != 7 +#error This code assumes the SBE-XIP header version 7 layout +#endif + + o_dest->iv_id = revle32(i_src->iv_id); + o_dest->iv_data = revle32(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 + +static int +finalSection(const void* i_image, int* o_sectionId) +{ + int i, rc; + uint32_t offset; + SbeXipHeader hostHeader; + + sbe_xip_translate_header(&hostHeader, (SbeXipHeader*)i_image); + + offset = 0; + for (i = 0; i < SBE_XIP_SECTIONS; i++) { + if (hostHeader.iv_section[i].iv_offset > offset) { + *o_sectionId = i; + offset = hostHeader.iv_section[i].iv_offset; + } + } + if (offset == 0) { + rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR, "The image is empty\n"); + } else { + rc = 0; + } + return rc; +} + + +/// Return a pointer to an image-format section table entry + +static int +getSectionPointer(const void* i_image, + const int i_sectionId, + SbeXipSection** o_imageSection) +{ + int rc; + + if ((i_sectionId < 0) || (i_sectionId >= SBE_XIP_SECTIONS)) { + rc = TRACE_ERROR(SBE_XIP_INVALID_ARGUMENT); + } else { + *o_imageSection = + &(((SbeXipHeader*)i_image)->iv_section[i_sectionId]); + rc = 0; + } + return rc; +} + + +/// Restore a section table entry from host format to image format. + +static int +putSection(const void* i_image, + const int i_sectionId, + SbeXipSection* i_hostSection) +{ + int rc; + SbeXipSection *imageSection; + + rc = getSectionPointer(i_image, i_sectionId, &imageSection); + + if (!rc) { + translateSection(imageSection, i_hostSection); + } + + return rc; +} + + +/// Set the offset of a section + +static int +setSectionOffset(void* io_image, const int i_section, const uint32_t i_offset) +{ + SbeXipSection* section; + int rc; + + rc = getSectionPointer(io_image, i_section, §ion); + if (!rc) { + section->iv_offset = revle32(i_offset); + } + return rc; +} + + +/// Set the size of a section + +static int +setSectionSize(void* io_image, const int i_section, const uint32_t i_size) +{ + SbeXipSection* section; + int rc; + + rc = getSectionPointer(io_image, i_section, §ion); + if (!rc) { + section->iv_size = revle32(i_size); + } + return rc; +} + + +/// Translate a PORE address in the image to a section and offset + +// We first check to be sure that the PORE 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. + +static int +pore2Section(const void* i_image, + const uint64_t i_poreAddress, + int* o_section, + uint32_t* o_offset) +{ + int rc, sectionId; + SbeXipSection section; + uint32_t addressOffset; + + do { + rc = 0; + + if ((i_poreAddress < linkAddress(i_image)) || + (i_poreAddress > (linkAddress(i_image) + imageSize(i_image)))) { + rc = TRACE_ERRORX(SBE_XIP_INVALID_ARGUMENT, + "pore2section: The i_poreAddress argument " + "(" F0x016llx ")\nis outside the bounds of the " + "image (" F0x016llx ":" F0x016llx ")\n", + i_poreAddress, + linkAddress(i_image), + linkAddress(i_image) + imageSize(i_image)); + break; + } + + addressOffset = (i_poreAddress - linkAddress(i_image)) & 0xffffffff; + + for (sectionId = 0; sectionId < SBE_XIP_SECTIONS; sectionId++) { + rc = sbe_xip_get_section(i_image, sectionId, §ion); + if (rc) { + rc = TRACE_ERROR(SBE_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 == SBE_XIP_SECTIONS) { + rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR, + "Error processing PORE address " F0x016llx ". " + "The address is not mapped in any section.\n" + "A section table dump appears below\n", + i_poreAddress); + dumpSectionTable(i_image); + break; + } + + *o_section = sectionId; + *o_offset = addressOffset - section.iv_offset; + + } while(0); + + return rc; +} + + +/// Get the information required to search the TOC. +/// +/// All return values are optional. + +static int +getToc(void* i_image, + SbeXipToc** o_toc, + size_t* o_entries, + int* o_sorted, + char** o_strings) +{ + int rc; + SbeXipSection tocSection, stringsSection; + + do { + rc = sbe_xip_get_section(i_image, SBE_XIP_SECTION_TOC, &tocSection); + if (rc) break; + + rc = sbe_xip_get_section(i_image, SBE_XIP_SECTION_STRINGS, + &stringsSection); + if (rc) break; + + if (o_toc) { + *o_toc = (SbeXipToc*)((uint8_t*)i_image + tocSection.iv_offset); + } + if (o_entries) { + *o_entries = tocSection.iv_size / sizeof(SbeXipToc); + } + if (o_sorted) { + *o_sorted = sorted(i_image); + } + if (o_strings) { + *o_strings = (char*)i_image + stringsSection.iv_offset; + } + } while (0); + return rc; +} + + +/// Compare two normalized TOC entries for sorting. + +static int +compareToc(const SbeXipToc* i_a, const SbeXipToc* i_b, + const char* i_strings) +{ + return strcmp(i_strings + revle32(i_a->iv_id), + i_strings + revle32(i_b->iv_id)); +} + + +/// Iterative quicksort of the TOC + +// Note: The stack requirement is limited to 256 bytes + minor local storage. + +static void +quickSort(SbeXipToc* io_toc, int i_left, int i_right, + const char* i_strings) +{ + int i, j, left, right, sp; + SbeXipToc 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 (compareToc(&(io_toc[i]), &pivot, i_strings) < 0) { + i++; + } + while (compareToc(&(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 + +static int +linearSearch(void* i_image, const char* i_id, SbeXipToc** o_entry) +{ + int rc; + SbeXipToc *imageToc, hostToc; + size_t entries; + char* strings; + + *o_entry = 0; + rc = getToc(i_image, &imageToc, &entries, 0, &strings); + if (!rc) { + for (; entries; entries--, imageToc++) { + translateToc(&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(SBE_XIP_ITEM_NOT_FOUND); + } + } + return rc; +} + + +/// A classic binary search of a (presumed) sorted array + +static int +binarySearch(void* i_image, const char* i_id, SbeXipToc** o_entry) +{ + int rc; + SbeXipToc *imageToc; + size_t entries; + char* strings; + int sorted, left, right, next, sort; + + do { + *o_entry = 0; + + rc = getToc(i_image, &imageToc, &entries, &sorted, &strings); + if (rc) break; + + if (!sorted) { + rc = TRACE_ERROR(SBE_XIP_BUG); + break; + } + + left = 0; + right = entries - 1; + while (left <= right) { + next = (left + right) / 2; + sort = strcmp(i_id, strings + revle32(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(SBE_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. + +static int +validateTocEntry(void* io_image, const SbeXipItem* i_item, void* io_arg) +{ + int rc; + SbeXipItem found; + + do { + rc = sbe_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(SBE_XIP_TOC_ERROR, + "Duplicate TOC entry for '%s'\n", i_item->iv_id); + } + break; + } while (0); + return rc; +} + + +/// 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. + +static int +normalizeToc(void* io_image, SbeXipToc *io_imageToc) +{ + SbeXipToc hostToc; + int idSection, dataSection; + uint32_t idOffset, dataOffset; + 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. + + translateToc(&hostToc, io_imageToc); + + rc = pore2Section(io_image, + fullAddress(io_image, hostToc.iv_id), + &idSection, + &idOffset); + if (rc) break; + + if (idSection != SBE_XIP_SECTION_STRINGS) { + rc = TRACE_ERROR(SBE_XIP_IMAGE_ERROR); + break; + } + + rc = pore2Section(io_image, + fullAddress(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; + + // Finally update the TOC entry + + translateToc(io_imageToc, &hostToc); + + } while (0); + + return rc; +} + + +/// Decode a normalized image-format TOC entry into a host-format SbeXipItem +/// structure + +static int +decodeToc(void* i_image, + SbeXipToc* i_imageToc, + SbeXipItem* o_item) +{ + int rc; + SbeXipToc hostToc; + SbeXipSection dataSection, stringsSection; + + do { + if (!normalized(i_image)) { + rc = TRACE_ERROR(SBE_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. + + translateToc(&hostToc, i_imageToc); + + o_item->iv_toc = i_imageToc; + o_item->iv_type = hostToc.iv_type; + o_item->iv_elements = hostToc.iv_elements; + + sbe_xip_get_section(i_image, SBE_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 = sbe_xip_get_section(i_image, hostToc.iv_section, &dataSection); + if (rc) break; + + if (dataSection.iv_size == 0) { + rc = TRACE_ERROR(SBE_XIP_DATA_NOT_PRESENT); + break; + } + + o_item->iv_imageData = + (void*)((uint8_t*)i_image + + dataSection.iv_offset + hostToc.iv_data); + + o_item->iv_address = + linkAddress(i_image) + dataSection.iv_offset + hostToc.iv_data; + + } while (0); + return rc; +} + + +/// Sort the TOC + +static int +sortToc(void* io_image) +{ + int rc; + SbeXipToc *hostToc; + size_t entries; + char* strings; + + do { + rc = quickCheck(io_image, 1); + if (rc) break; + + if (sorted(io_image)) break; + + rc = getToc(io_image, &hostToc, &entries, 0, &strings); + if (rc) break; + + quickSort(hostToc, 0, entries - 1, strings); + + ((SbeXipHeader*)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. + +static int +padImage(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(SBE_XIP_INVALID_ARGUMENT, + "Alignment specification (%u) " + "not a power-of-2\n", + i_align); + break; + } + + *pad = imageSize(io_image) % i_align; + if (*pad != 0) { + *pad = i_align - *pad; + + if ((imageSize(io_image) + *pad) > i_allocation) { + rc = TRACE_ERROR(SBE_XIP_WOULD_OVERFLOW); + break; + } + + memset((void*)((unsigned long)io_image + imageSize(io_image)), + 0, *pad); + setImageSize(io_image, imageSize(io_image) + *pad); + } + } while (0); + + return rc; +} + + +//////////////////////////////////////////////////////////////////////////// +// Published API +//////////////////////////////////////////////////////////////////////////// + +int +sbe_xip_validate(void* i_image, const uint32_t i_size) +{ + SbeXipHeader hostHeader; + int rc = 0, i; + uint32_t linkAddress, imageSize, extent, offset, size; + uint8_t alignment; + + sbe_xip_translate_header(&hostHeader, (SbeXipHeader*)i_image); + + do { + + // Validate C/Assembler constraints. + + if (sizeof(SbeXipSection) != SIZE_OF_SBE_XIP_SECTION) { + rc = TRACE_ERRORX(SBE_XIP_BUG, + "C/Assembler size mismatch(%d/%d) " + "for SbeXipSection\n", + sizeof(SbeXipSection), SIZE_OF_SBE_XIP_SECTION); + break; + } + + if (sizeof(SbeXipToc) != SIZE_OF_SBE_XIP_TOC) { + rc = TRACE_ERRORX(SBE_XIP_BUG, + "C/Assembler size mismatch(%d/%d) " + "for SbeXipToc\n", + sizeof(SbeXipToc), SIZE_OF_SBE_XIP_TOC); + break; + } + + // Validate the image pointer and magic number + + rc = quickCheck(i_image, 0); + if (rc) break; + + // Validate the image size + + linkAddress = hostHeader.iv_linkAddress; + imageSize = hostHeader.iv_imageSize; + extent = linkAddress + imageSize; + + if (imageSize < sizeof(SbeXipHeader)) { + rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR, + "sbe_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(SBE_XIP_IMAGE_ERROR, + "sbe_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(SBE_XIP_IMAGE_ERROR, + "sbe_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 % SBE_XIP_FINAL_ALIGNMENT) != 0) { + rc = TRACE_ERRORX(SBE_XIP_ALIGNMENT_ERROR, + "sbe_xip_validate(%p, %u) : " + "The image size (%u) is not a multiple of %u\n", + i_image, i_size, imageSize, + SBE_XIP_FINAL_ALIGNMENT); + break; + } + + // Validate that all sections appear to be within the image + // bounds, and are aligned correctly. + + for (i = 0; i < SBE_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(SBE_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(SBE_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[SBE_XIP_SECTION_TOC].iv_size; + if (size != 0) { + if (normalized(i_image)) { + rc = sbe_xip_map_toc(i_image, validateTocEntry, 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 +sbe_xip_normalize(void* io_image) +{ + int rc, i; + SbeXipSection section; + SbeXipToc* imageToc; + size_t entries; + + do { + rc = quickCheck(io_image, 0); + if (rc) break; + + if (!normalized(io_image)) { + rc = getToc(io_image, &imageToc, &entries, 0, 0); + if (rc) break; + for (; entries--; imageToc++) { + rc = normalizeToc(io_image, imageToc); + if (rc) break; + } + if (rc) break; + ((SbeXipHeader*)io_image)->iv_normalized = 1; + } + + rc = sortToc(io_image); + if (rc) break; + + for (i = 0; i < SBE_XIP_SECTIONS; i++) { + rc = sbe_xip_get_section(io_image, i, §ion); + if (rc) break; + if (section.iv_size == 0) { + setSectionOffset(io_image, i, 0); + } + } + if (rc) break; + + } while(0); + + ((SbeXipHeader*)io_image)->iv_normalized = (rc == 0); + + return rc; +} + + +int +sbe_xip_image_size(void* io_image, uint32_t* o_size) +{ + int rc; + + rc = quickCheck(io_image, 0); + if (!rc) { + *o_size = imageSize(io_image); + } + return rc; +} + + +int +sbe_xip_get_section(const void* i_image, + const int i_sectionId, + SbeXipSection* o_hostSection) +{ + int rc; + SbeXipSection *imageSection; + + rc = getSectionPointer(i_image, i_sectionId, &imageSection); + + if (!rc) { + translateSection(o_hostSection, imageSection); + } + + return rc; +} + + +int +sbe_xip_find(void* i_image, + const char* i_id, + SbeXipItem* o_item) +{ + int rc; + SbeXipToc* toc; + SbeXipItem item, *pitem; + + do { + rc = quickCheck(i_image, 1); + if (rc) break; + + if (sorted(i_image)) { + rc = binarySearch(i_image, i_id, &toc); + } else { + rc = linearSearch(i_image, i_id, &toc); + } + if (rc) break; + + if (o_item) { + pitem = o_item; + } else { + pitem = &item; + } + rc = decodeToc(i_image, toc, pitem); + if (rc) break; + + } while (0); + + return rc; +} + + +int +sbe_xip_map_halt(void* io_image, + int (*i_fn)(void* io_image, + const uint64_t i_poreAddress, + const char* i_rcString, + void* io_arg), + void* io_arg) +{ + int rc; + SbeXipSection haltSection; + SbeXipHalt *halt; + uint32_t size; + uint32_t actualSize; + + do { + rc = quickCheck(io_image, 0); + if (rc) break; + + rc = sbe_xip_get_section(io_image, SBE_XIP_SECTION_HALT, &haltSection); + if (rc) break; + + halt = (SbeXipHalt*)((unsigned long)io_image + haltSection.iv_offset); + size = haltSection.iv_size; + + while (size) { + + rc = i_fn(io_image, + revle64(halt->iv_address), + halt->iv_string, + io_arg); + if (rc) break; + + // The SbeXipHalt structure claims a 4-character string. The + // computation below computes the actual record size based on the + // actual length of the string, including the 0-byte termination. + + actualSize = 8 + (((strlen(halt->iv_string) + 4) / 4) * 4); + + if (size < actualSize) { + rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR, + "The .halt section is improperly formed\n"); + break; + } + + size -= actualSize; + halt = (SbeXipHalt*)((unsigned long)halt + actualSize); + }; + + if (rc) break; + + } while (0); + + return rc; +} + + +typedef struct { + uint64_t iv_address; + const char* iv_string; +} GetHaltStruct; + + +static int +getHaltMap(void* io_image, + const uint64_t i_poreAddress, + const char* i_rcString, + void* io_arg) +{ + int rc; + + GetHaltStruct* s = (GetHaltStruct*)io_arg; + + if (i_poreAddress == s->iv_address) { + s->iv_string = i_rcString; + rc = -1; + } else { + rc = 0; + } + + return rc; +} + + +int +sbe_xip_get_halt(void* io_image, + const uint64_t i_poreAddress, + const char** o_rcString) +{ + int rc; + GetHaltStruct s; + + s.iv_address = i_poreAddress; + do { + rc = quickCheck(io_image, 0); + if (rc) break; + + rc = sbe_xip_map_halt(io_image, getHaltMap, &s); + if (rc == 0) { + rc = TRACE_ERRORX(SBE_XIP_ITEM_NOT_FOUND, + "sbe_xip_get_halt: No HALT code is associated " + "with address " F0x012llx "\n", i_poreAddress); + } else if (rc < 0) { + *o_rcString = s.iv_string; + rc = 0; + } + } while (0); + + return rc; +} + + +int +sbe_xip_get_scalar(void *i_image, const char* i_id, uint64_t* o_data) +{ + int rc; + SbeXipItem item; + + rc = sbe_xip_find(i_image, i_id, &item); + if (!rc) { + switch (item.iv_type) { + case SBE_XIP_UINT8: + *o_data = *((uint8_t*)(item.iv_imageData)); + break; + case SBE_XIP_UINT32: + *o_data = revle32(*((uint32_t*)(item.iv_imageData))); + break; + case SBE_XIP_UINT64: + *o_data = revle64(*((uint64_t*)(item.iv_imageData))); + break; + case SBE_XIP_ADDRESS: + *o_data = item.iv_address; + break; + default: + rc = TRACE_ERROR(SBE_XIP_TYPE_ERROR); + break; + } + } + return rc; +} + + +int +sbe_xip_get_element(void *i_image, + const char* i_id, + const uint32_t i_index, + uint64_t* o_data) +{ + int rc; + SbeXipItem item; + + do { + rc = sbe_xip_find(i_image, i_id, &item); + if (rc) break; + + if ((item.iv_elements != 0) && (i_index >= item.iv_elements)) { + rc = TRACE_ERROR(SBE_XIP_BOUNDS_ERROR); + break; + } + + switch (item.iv_type) { + case SBE_XIP_UINT8: + *o_data = ((uint8_t*)(item.iv_imageData))[i_index]; + break; + case SBE_XIP_UINT32: + *o_data = revle32(((uint32_t*)(item.iv_imageData))[i_index]); + break; + case SBE_XIP_UINT64: + *o_data = revle64(((uint64_t*)(item.iv_imageData))[i_index]); + break; + default: + rc = TRACE_ERROR(SBE_XIP_TYPE_ERROR); + break; + } + if (rc) break; + + } while (0); + return rc; +} + + +int +sbe_xip_get_string(void *i_image, const char* i_id, char** o_data) +{ + int rc; + SbeXipItem item; + + rc = sbe_xip_find(i_image, i_id, &item); + if (!rc) { + switch (item.iv_type) { + case SBE_XIP_STRING: + *o_data = (char*)(item.iv_imageData); + break; + default: + rc = TRACE_ERROR(SBE_XIP_TYPE_ERROR); + break; + } + } + return rc; +} + + +int +sbe_xip_read_uint64(const void *i_image, + const uint64_t i_poreAddress, + uint64_t* o_data) +{ + int rc; + + do { + rc = quickCheck(i_image, 0); + if (rc) break; + + rc = validatePoreAddress(i_image, i_poreAddress, 8); + if (rc) break; + + if (i_poreAddress % 8) { + rc = TRACE_ERROR(SBE_XIP_ALIGNMENT_ERROR); + break; + } + + *o_data = + revle64(*((uint64_t*)pore2Host(i_image, i_poreAddress))); + + } while(0); + + return rc; +} + + +int +sbe_xip_set_scalar(void* io_image, const char* i_id, const uint64_t i_data) +{ + int rc; + SbeXipItem item; + + rc = sbe_xip_find(io_image, i_id, &item); + if (!rc) { + switch(item.iv_type) { + case SBE_XIP_UINT8: + *((uint8_t*)(item.iv_imageData)) = (uint8_t)i_data; + break; + case SBE_XIP_UINT32: + *((uint32_t*)(item.iv_imageData)) = revle32((uint32_t)i_data); + break; + case SBE_XIP_UINT64: + *((uint64_t*)(item.iv_imageData)) = revle64((uint64_t)i_data); + break; + default: + rc = TRACE_ERROR(SBE_XIP_TYPE_ERROR); + break; + } + } + return rc; +} + + +int +sbe_xip_set_element(void *i_image, + const char* i_id, + const uint32_t i_index, + const uint64_t i_data) +{ + int rc; + SbeXipItem item; + + do { + rc = sbe_xip_find(i_image, i_id, &item); + if (rc) break; + + if ((item.iv_elements != 0) && (i_index >= item.iv_elements)) { + rc = TRACE_ERROR(SBE_XIP_BOUNDS_ERROR); + break; + } + + switch (item.iv_type) { + case SBE_XIP_UINT8: + ((uint8_t*)(item.iv_imageData))[i_index] = (uint8_t)i_data; + break; + case SBE_XIP_UINT32: + ((uint32_t*)(item.iv_imageData))[i_index] = + revle32((uint32_t)i_data); + break; + case SBE_XIP_UINT64: + ((uint64_t*)(item.iv_imageData))[i_index] = + revle64((uint64_t)i_data); + break; + default: + rc = TRACE_ERROR(SBE_XIP_TYPE_ERROR); + break; + } + if (rc) break; + + } while (0); + + return rc; +} + + +int +sbe_xip_set_string(void *i_image, const char* i_id, const char* i_data) +{ + int rc; + SbeXipItem item; + char* dest; + + rc = sbe_xip_find(i_image, i_id, &item); + if (!rc) { + switch (item.iv_type) { + case SBE_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(SBE_XIP_TYPE_ERROR); + break; + } + } + return rc; +} + + +int +sbe_xip_write_uint64(void *io_image, + const uint64_t i_poreAddress, + const uint64_t i_data) +{ + int rc; + + do { + rc = quickCheck(io_image, 0); + if (rc) break; + + rc = validatePoreAddress(io_image, i_poreAddress, 8); + if (rc) break; + + if (i_poreAddress % 8) { + rc = TRACE_ERROR(SBE_XIP_ALIGNMENT_ERROR); + break; + } + + *((uint64_t*)pore2Host(io_image, i_poreAddress)) = revle64(i_data); + + } while(0); + + return rc; +} + + +int +sbe_xip_delete_section(void* io_image, const int i_sectionId) +{ + int rc, final; + SbeXipSection section; + + do { + rc = quickCheck(io_image, 1); + if (rc) break; + + rc = sbe_xip_get_section(io_image, i_sectionId, §ion); + if (rc) break; + + + // Deleting an empty section is a NOP. Otherwise the section must be + // the final section of the image. Update the sizes and re-establish + // the final image alignment. + + if (section.iv_size == 0) break; + + rc = finalSection(io_image, &final); + if (rc) break; + + if (final != i_sectionId) { + rc = TRACE_ERRORX(SBE_XIP_SECTION_ERROR, + "Attempt to delete non-final section %d\n", + i_sectionId); + break; + } + + setImageSize(io_image, section.iv_offset); + setSectionOffset(io_image, i_sectionId, 0); + setSectionSize(io_image, i_sectionId, 0); + + finalAlignment(io_image); + + } while (0); + + return rc; +} + + +int +sbe_xip_duplicate_section(const void* i_image, + const int i_sectionId, + void** o_duplicate, + uint32_t* o_size) +{ + SbeXipSection section; + int rc; + + *o_duplicate = 0; + + do { + rc = quickCheck(i_image, 0); + if (rc) break; + + rc = sbe_xip_get_section(i_image, i_sectionId, §ion); + if (rc) break; + + if (section.iv_size == 0) { + rc = TRACE_ERRORX(SBE_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(SBE_XIP_NO_MEMORY); + break; + } + + memcpy(*o_duplicate, + hostAddressFromOffset(i_image, section.iv_offset), + section.iv_size); + + + } while (0); + + if (rc) { + free(*o_duplicate); + *o_duplicate = 0; + *o_size = 0; + } + + return rc; +} + + +int +sbe_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) +{ + SbeXipSection section; + int rc, final; + void* hostAddress; + uint32_t pad; + + do { + rc = quickCheck(io_image, 1); + if (rc) break; + + rc = sbe_xip_get_section(io_image, i_sectionId, §ion); + if (rc) break; + + if (i_size == 0) break; + + 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 = padImage(io_image, i_allocation, section.iv_alignment, &pad); + if (rc) break; + section.iv_offset = imageSize(io_image); + + } else { + + // Otherwise, the section must be the final section in order to + // continue. Remove any padding from the image. + + rc = finalSection(io_image, &final); + if (rc) break; + + if (final != i_sectionId) { + rc = TRACE_ERRORX(SBE_XIP_SECTION_ERROR, + "Attempt to append to non-final section " + "%d\n", i_sectionId); + break; + } + setImageSize(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 ((imageSize(io_image) + i_size) > i_allocation) { + rc = TRACE_ERROR(SBE_XIP_WOULD_OVERFLOW); + break; + } + if (o_sectionOffset != 0) { + *o_sectionOffset = section.iv_size; + } + + hostAddress = hostAddressFromOffset(io_image, imageSize(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. + + setImageSize(io_image, imageSize(io_image) + i_size); + finalAlignment(io_image); + + section.iv_size += i_size; + rc = putSection(io_image, i_sectionId, §ion); + if (rc) break; + + + // Special case + + if (i_sectionId == SBE_XIP_SECTION_TOC) { + ((SbeXipHeader*)io_image)->iv_tocSorted = 0; + } + + } while (0); + + return rc; +} + + +int +sbe_xip_section2pore(const void* i_image, + const int i_sectionId, + const uint32_t i_offset, + uint64_t* o_poreAddress) +{ + int rc; + SbeXipSection section; + + do { + rc = quickCheck(i_image, 0); + if (rc) break; + + rc = sbe_xip_get_section(i_image, i_sectionId, §ion); + if (rc) break; + + if (section.iv_size == 0) { + rc = TRACE_ERROR(SBE_XIP_SECTION_ERROR); + break; + } + + if (i_offset > (section.iv_offset + section.iv_size)) { + rc = TRACE_ERROR(SBE_XIP_INVALID_ARGUMENT); + break; + } + + *o_poreAddress = linkAddress(i_image) + section.iv_offset + i_offset; + + if (*o_poreAddress % 4) { + rc = TRACE_ERROR(SBE_XIP_ALIGNMENT_ERROR); + break; + } + + } while(0); + + return rc; +} + + +int +sbe_xip_pore2section(const void* i_image, + const uint64_t i_poreAddress, + int* i_section, + uint32_t* i_offset) +{ + int rc; + + do { + rc = quickCheck(i_image, 0); + if (rc) break; + + rc = pore2Section(i_image, i_poreAddress, i_section, i_offset); + + } while(0); + + return rc; +} + + +int +sbe_xip_pore2host(const void* i_image, + const uint64_t i_poreAddress, + void** o_hostAddress) +{ + int rc; + + do { + rc = quickCheck(i_image, 0); + if (rc) break; + + if ((i_poreAddress < linkAddress(i_image)) || + (i_poreAddress > (linkAddress(i_image) + imageSize(i_image)))) { + rc = TRACE_ERROR(SBE_XIP_INVALID_ARGUMENT); + break; + } + + *o_hostAddress = + hostAddressFromOffset(i_image, + i_poreAddress - linkAddress(i_image)); + } while(0); + + return rc; +} + + +int +sbe_xip_host2pore(const void* i_image, + void* i_hostAddress, + uint64_t* o_poreAddress) +{ + int rc; + + do { + rc = quickCheck(i_image, 0); + if (rc) break; + + if ((i_hostAddress < i_image) || + (i_hostAddress > hostAddressFromOffset(i_image, imageSize(i_image)))) { + rc = TRACE_ERROR(SBE_XIP_INVALID_ARGUMENT); + break; + } + + *o_poreAddress = linkAddress(i_image) + + ((unsigned long)i_hostAddress - (unsigned long)i_image); + if (*o_poreAddress % 4) { + rc = TRACE_ERROR(SBE_XIP_ALIGNMENT_ERROR); + break; + } + } while(0); + + return rc; +} + + +void +sbe_xip_translate_header(SbeXipHeader* o_dest, const SbeXipHeader* i_src) +{ +#ifndef _BIG_ENDIAN + int i; + SbeXipSection* destSection; + const SbeXipSection* srcSection; + +#if SBE_XIP_HEADER_VERSION != 7 +#error This code assumes the SBE-XIP header version 7 layout +#endif + + o_dest->iv_magic = revle64(i_src->iv_magic); + o_dest->iv_entryOffset = revle64(i_src->iv_entryOffset); + o_dest->iv_linkAddress = revle64(i_src->iv_linkAddress); + + for (i = 0; i < 5; i++) { + o_dest->iv_reserved64[i] = 0; + } + + for (i = 0, destSection = o_dest->iv_section, + srcSection = i_src->iv_section; + i < SBE_XIP_SECTIONS; + i++, destSection++, srcSection++) { + translateSection(destSection, srcSection); + } + + o_dest->iv_imageSize = revle32(i_src->iv_imageSize); + o_dest->iv_buildDate = revle32(i_src->iv_buildDate); + o_dest->iv_buildTime = revle32(i_src->iv_buildTime); + + for (i = 0; i < 5; i++) { + o_dest->iv_reserved32[i] = 0; + } + + o_dest->iv_headerVersion = i_src->iv_headerVersion; + o_dest->iv_normalized = i_src->iv_normalized; + o_dest->iv_tocSorted = i_src->iv_tocSorted; + + for (i = 0; i < 3; i++) { + o_dest->iv_reserved8[i] = 0; + } + + memcpy(o_dest->iv_buildUser, i_src->iv_buildUser, + sizeof(i_src->iv_buildUser)); + memcpy(o_dest->iv_buildHost, i_src->iv_buildHost, + sizeof(i_src->iv_buildHost)); + memcpy(o_dest->iv_reservedChar, i_src->iv_reservedChar, + sizeof(i_src->iv_reservedChar)); + +#else + if (o_dest != i_src) { + *o_dest = *i_src; + } +#endif /* _BIG_ENDIAN */ +} + + +int +sbe_xip_map_toc(void* io_image, + int (*i_fn)(void* io_image, + const SbeXipItem* i_item, + void* io_arg), + void* io_arg) +{ + int rc; + SbeXipToc *imageToc; + SbeXipItem item; + size_t entries; + + do { + rc = quickCheck(io_image, 0); + if (rc) break; + + rc = getToc(io_image, &imageToc, &entries, 0, 0); + if (rc) break; + + for (; entries--; imageToc++) { + rc = decodeToc(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/usr/hwpf/hwp/build_winkle_images/proc_slw_build/sbe_xip_image.h b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/sbe_xip_image.h new file mode 100644 index 000000000..081f368e8 --- /dev/null +++ b/src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/sbe_xip_image.h @@ -0,0 +1,1679 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/hwpf/hwp/build_winkle_images/proc_slw_build/sbe_xip_image.h $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +#ifndef __SBE_XIP_IMAGE_H +#define __SBE_XIP_IMAGE_H + +// $Id: sbe_xip_image.h,v 1.15 2012/05/22 03:26:27 bcbrock Exp $ +// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ipl/sbe/sbe_xip_image.h,v $ +//----------------------------------------------------------------------------- +// *! (C) Copyright International Business Machines Corp. 2011 +// *! All Rights Reserved -- Property of IBM +// *! *** IBM Confidential *** +//----------------------------------------------------------------------------- +// *! OWNER NAME: Bishop Brock Email: bcbrock@us.ibm.com +//------------------------------------------------------------------------------ + +/// \file sbe_xip_image.h +/// \brief Everything related to creating and manipulating SBE-XIP binary +/// images. + +#include "fapi_sbe_common.H" + +/// Current version (fields, layout, sections) of the SBE_XIP header +/// +/// If any changes are made to this file or to sbe_xip_header.H, please update +/// the header version and follow-up on all of the error messages. + +#define SBE_XIP_HEADER_VERSION 7 + +/// \defgroup sbe_xip_magic_numbers SBE-XIP magic numbers +/// +/// An SBE-XIP magic number is a 64-bit constant. The 4 high-order bytes +/// contain the ASCII characters "XIP " and identify the image as an SBE-XIP +/// image, while the 4 low-order bytes identify the type of the image. +/// +/// @{ + +#define SBE_XIP_MAGIC 0x58495020 // "XIP " +#define SBE_BASE_MAGIC ULL(0x5849502042415345) // "XIP BASE" +#define SBE_SEEPROM_MAGIC ULL(0x584950205345504d) // "XIP SEPM" +#define SBE_CENTAUR_MAGIC ULL(0x58495020434e5452) // "XIP CNTR" + +/// @} + + +/// \defgroup sbe_xip_sections SBE-XIP Image Section Indexes +/// +/// These constants define the order that the SbeXipSection structures appear +/// in the header, which is not necessarily the order the sections appear in +/// the binary image. Given that SBE-XIP image contents are tightly +/// controlled, we use this simple indexing scheme for the allowed sections +/// rather than a more general approach, e.g., allowing arbitrary sections +/// identified by their names. +/// +/// @{ + +// -*- DO NOT REORDER OR EDIT THIS SET OF CONSTANTS WITHOUT ALSO EDITING -*- +// -*- THE ASSEMBLER LAYOUT IN sbe_xip_header.S. -*- + +#define SBE_XIP_SECTION_HEADER 0 +#define SBE_XIP_SECTION_FIXED 1 +#define SBE_XIP_SECTION_IPL_TEXT 2 +#define SBE_XIP_SECTION_IPL_DATA 3 +#define SBE_XIP_SECTION_TEXT 4 +#define SBE_XIP_SECTION_DATA 5 +#define SBE_XIP_SECTION_TOC 6 +#define SBE_XIP_SECTION_STRINGS 7 +#define SBE_XIP_SECTION_PIBMEM0 8 +#define SBE_XIP_SECTION_PIBMEM1 9 +#define SBE_XIP_SECTION_RINGS 10 +#define SBE_XIP_SECTION_HALT 11 +#define SBE_XIP_SECTION_SLW 12 +#define SBE_XIP_SECTION_RESERVED_2 13 +#define SBE_XIP_SECTION_RESERVED_1 14 +#define SBE_XIP_SECTION_RESERVED_0 15 + +#define SBE_XIP_SECTIONS 16 + +/// @} + +#ifndef __ASSEMBLER__ + +/// Applications can expand this macro to create an array of section names. +#define SBE_XIP_SECTION_NAMES(var) \ + const char* var[] = { \ + ".header", \ + ".fixed", \ + ".ipl_text", \ + ".ipl_data", \ + ".text", \ + ".data", \ + ".toc", \ + ".strings", \ + ".pibmem0", \ + ".pibmem1", \ + ".rings", \ + ".halt", \ + ".slw", \ + ".reserved_2", \ + ".reserved_1", \ + ".reserved_0" \ + } + +/// Applications can use this macro to safely index the array of section +/// names. +#define SBE_XIP_SECTION_NAME(var, n) \ + ((((n) < 0) || ((n) > (int)(sizeof(var) / sizeof(char*)))) ? \ + "Bug : Invalid SBE-XIP section name" : var[n]) + + +#endif /* __ASSEMBLER__ */ + + +/// Maximum section alignment for SBE-XIP sections +#define SBE_XIP_MAX_SECTION_ALIGNMENT 128 + +/// defgroup sbe_xip_toc_types SBE-XIP Table of Contents data types +/// +/// These are the data types stored in the \a iv_type field of the SbeXipToc +/// objects. These must be defined as manifest constants because they are +/// required to be recognized as manifest constants in C (as opposed to C++) +/// code. +/// +/// NB: The 0x0 code is purposefully left undefined to catch bugs. +/// +/// @{ + +/// Data is a single unsigned byte +#define SBE_XIP_UINT8 0x01 + +/// Data is a 32-bit unsigned integer +#define SBE_XIP_UINT32 0x02 + +/// Data is a 64-bit unsigned integer +#define SBE_XIP_UINT64 0x03 + +/// Data is a 0-byte terminated ASCII string +#define SBE_XIP_STRING 0x04 + +/// Data is an address +#define SBE_XIP_ADDRESS 0x05 + +/// The maximum type number +#define SBE_XIP_MAX_TYPE_INDEX 0x05 + +/// Applications can expand this macro to get access to string forms of the +/// SBE-XIP data types if desired. +#define SBE_XIP_TYPE_STRINGS(var) \ + const char* var[] = { \ + "Illegal 0 Code", \ + "SBE_XIP_UINT8", \ + "SBE_XIP_UINT32", \ + "SBE_XIP_UINT64", \ + "SBE_XIP_STRING", \ + "SBE_XIP_ADDRESS", \ + } + +/// Applications can expand this macro to get access to abbreviated string +/// forms of the SBE-XIP data types if desired. +#define SBE_XIP_TYPE_ABBREVS(var) \ + const char* var[] = { \ + "Illegal 0 Code", \ + "u8 ", \ + "u32", \ + "u64", \ + "str", \ + "adr", \ + } + +/// Applications can use this macro to safely index either array of SBE-XIP +/// type strings. +#define SBE_XIP_TYPE_STRING(var, n) \ + (((n) > (sizeof(var) / sizeof(char*))) ? \ + "Invalid SBE-XIP type specification" : var[n]) + +/// @} + + +/// Final alignment constraint for SBE-XIP images. +/// +/// PORE images are required to be multiples of 8 bytes in length, to +/// gaurantee that the PoreVe will be able to complete any 8-byte load/store. +#define SBE_XIP_FINAL_ALIGNMENT 8 + + +//////////////////////////////////////////////////////////////////////////// +// C Definitions +//////////////////////////////////////////////////////////////////////////// + +#ifndef __ASSEMBLER__ + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} /* So __cplusplus doesn't mess w/auto-indent */ +#endif + +/// SBE-XIP Section information +/// +/// This structure defines the data layout of section table entries in the +/// SBE-XIP image header. + +// -*- DO NOT REORDER OR EDIT THIS STRUCTURE DEFINITION WITHOUT ALSO -*- +// -*- EDITING THE ASSEMBLER LAYOUT IN sbe_xip_header.H -*- + +typedef struct { + + /// The offset (in bytes) of the section from the beginning of the image + /// + /// In normalized images the section offset will always be 0 if the + /// section size is also 0. + uint32_t iv_offset; + + /// The size of the section in bytes, exclusive of alignment padding + /// + /// This is the size of the program-significant data in the section, + /// exclusive of any alignment padding or reserved or extra space. The + /// alignment padding (reserved space) is not represented explicitly, but + /// is only implied by the offset of any subsequent non-empty section, or + /// in the case of the final section in the image, the image size. + /// + /// Regardless of the \a iv_offset, if the \a iv_size of a section is 0 it + /// should be considered "not present" in the image. In normalized images + /// the section offset will always be 0 if the section size is also 0. + uint32_t iv_size; + + /// The required initial alignment for the section offset + /// + /// The PORE and the applications using SBE-XIP images have strict + /// alignment/padding requirements. The PORE does not handle any type of + /// unaligned instruction or data fetches. Some sections and subsections + /// must also be POWER cache-line aligned. The \a iv_alignment applies to + /// the first byte of the section. PORE images are also required to be + /// multiples of 8 bytes in length, to gaurantee that the PoreVe will be + /// able to complete any 8-byte load/store. These constraints are checked + /// by sbe_xip_validate() and enforced by sbe_xip_append(). The alignment + /// constraints may force a section to be padded, which may create "holes" + /// in the image as explained in the comments for the \a iv_size field. + /// + /// Note that alignment constraints are always checked relative to the + /// first byte of the image for in-memory images, not relative to the host + /// address. Alignment specifications are required to be a power-of-2. + uint8_t iv_alignment; + + /// Reserved structure alignment padding; Pad to 12 bytes + uint8_t iv_reserved8[3]; + +} SbeXipSection; + +/// The SbeXipSection structure is created by assembler code and is expected +/// to have the same size in C code. This constraint is checked in +/// sbe_xip_validate(). +#define SIZE_OF_SBE_XIP_SECTION 12 + + +/// SBE-XIP binary image header +/// +/// This header occupies the initial bytes of an SBE-XIP binary image. +/// The header contents are documented here, however the structure is actually +/// defined in the file sbe_xip_header.S, and these two definitions must be +/// kept consistent. +/// +/// The header is a fixed-format representation of the most critical +/// information about the image. The large majority of information about the +/// image and its contents are available through the searchable table of +/// contents. PORE code itself normally accesses the data directly through +/// global symbols. +/// +/// The header only contains information 1) required by OTPROM code (e.g., the +/// entry point); 2) required by search and updating APIs (e.g., the +/// locations and sizes of all of the sections.); a few pieces of critical +/// meta-data (e.g., information about the image build process). +/// +/// Any entries that are accessed by PORE code are required to be 64 bits, and +/// will appear at the beginning of the header. +/// +/// The header also contains bytewise offsets and sizes of all of the sections +/// that are assembled to complete the image. The offsets are relative to the +/// start of the image (where the header is loaded). The sizes include any +/// padding inserted by the link editor to guarantee section alignment. +/// +/// Every field of the header is also accesssible through the searchable table +/// of contents as documented in sbe_xip_header.S. + +// -*- DO NOT REORDER OR EDIT THIS STRUCTURE DEFINITION WITHOUT ALSO -*- +// -*- EDITING THE ASSEMBLER LAYOUT IN sbe_xip_header.S, AND WITHOUT -*- +// -*- UPDATING THE sbe_xip_translate_header() API IN sbe_xip_image.c. -*- + +typedef struct { + + ////////////////////////////////////////////////////////////////////// + // Identification - 8-byte aligned; 8 entries + ////////////////////////////////////////////////////////////////////// + + /// Contains SBE_XIP_MAGIC to identify an SBE-XIP image + uint64_t iv_magic; + + /// The offset of the SBE-XIP entry point from the start of the image + uint64_t iv_entryOffset; + + /// The base address used to link the image, as a full relocatable PORE + /// address + uint64_t iv_linkAddress; + + /// Reserved for future expansion + uint64_t iv_reserved64[5]; + + ////////////////////////////////////////////////////////////////////// + // Section Table - 4-byte aligned; 16 entries + ////////////////////////////////////////////////////////////////////// + + SbeXipSection iv_section[SBE_XIP_SECTIONS]; + + ////////////////////////////////////////////////////////////////////// + // Other information - 4-byte aligned; 8 entries + ////////////////////////////////////////////////////////////////////// + + /// The size of the image (including padding) in bytes + uint32_t iv_imageSize; + + /// Build date generated by `date +%Y%m%d`, e.g., 20110630 + uint32_t iv_buildDate; + + /// Build time generated by `date +%H%M`, e.g., 0756 + uint32_t iv_buildTime; + + /// Reserved for future expansion + uint32_t iv_reserved32[5]; + + ////////////////////////////////////////////////////////////////////// + // Other Information - 1-byte aligned; 8 entries + ////////////////////////////////////////////////////////////////////// + + /// Header format version number + uint8_t iv_headerVersion; + + /// Indicates whether the image has been normalized (0/1) + uint8_t iv_normalized; + + /// Indicates whether the TOC has been sorted to speed searching (0/1) + uint8_t iv_tocSorted; + + /// Reserved for future expansion + uint8_t iv_reserved8[5]; + + ////////////////////////////////////////////////////////////////////// + // Strings; 64 characters allocated + ////////////////////////////////////////////////////////////////////// + + /// Build user, generated by `id -un` + char iv_buildUser[16]; + + /// Build host, generated by `hostname` + char iv_buildHost[24]; + + /// Reserved for future expansion + char iv_reservedChar[24]; + +} SbeXipHeader; + + +/// A C-structure form of the SBE-XIP Table of Contents (TOC) entries +/// +/// The .toc section consists entirely of an array of these structures. +/// TOC entries are never accessed by PORE code. +/// +/// These structures store indexing information for global data required to be +/// manipulated by external tools. The actual data is usually allocated in a +/// data section and manipulated by the SBE code using global or local symbol +/// names. Each TOC entry contains a pointer to a keyword string naming the +/// data, the address of the data (or the data itself), the data type, +/// meta-information about the data, and for vectors the vector size. + +// -*- DO NOT REORDER OR EDIT THIS STRUCTURE DEFINITION WITHOUT ALSO -*- +// -*- EDITING THE ASSEMBLER MACROS (BELOW) THAT CREATE THE TABLE OF -*- +// -*- CONTENTS ENTRIES. -*- + +typedef struct { + + /// A pointer to a 0-byte terminated ASCII string identifying the data. + /// + /// When allocated by the .xip_toc macro this is a pointer to the string + /// form of the symbol name for the global or local symbol associated with + /// the data which is allocated in the .strings section. This pointer is + /// not aligned. + /// + /// When the image is normalized this pointer is replaced by the offset of + /// the string in the .strings section. + uint32_t iv_id; + + /// A 32-bit pointer locating the data + /// + /// This field is initially populated by the link editor. For scalar, + /// vector and string types this is the final relocated address of the + /// first byte of the data. For address types, this is the relocated + /// address. When the image is normalized, these addresses are converted + /// into the equivalent offsets from the beginning of the section holding + /// the data. + uint32_t iv_data; + + /// The type of the data; See \ref sbe_xip_toc_types. + uint8_t iv_type; + + /// The section containing the data; See \ref sbe_xip_sections. + uint8_t iv_section; + + /// The number of elements for vector types, otherwise 1 for scalar types + /// and addresses. + /// + /// Vectors are naturally limited in size, e.g. to the number of cores, + /// chips in a node, DD-levels etc. If \a iv_elements is 0 then no bounds + /// checking is done on get/set accesses of the data. + uint8_t iv_elements; + + /// Structure alignment padding; Pad to 12 bytes + uint8_t iv_pad; + +} SbeXipToc; + +/// The SbeXipToc structure is created by assembler code and is expected +/// to have the same size in C code. This constraint is checked in +/// sbe_xip_validate(). +#define SIZE_OF_SBE_XIP_TOC 12 + + +/// A decoded TOC entry for use by applications +/// +/// This structure is a decoded form of a normalized TOC entry, filled in by +/// the sbe_xip_decode_toc() and sbe_xip_find() APIs. This structure is +/// always returned with data elements in host-endian format. +/// +/// \note Only special-purpose applications will ever need to use this +/// structure given that the higher-level APIs sbe_xip_get_*() and +/// sbe_xip_set_*() are provided and shoudl be used if possible. + +typedef struct { + + /// A pointer to the associated TOC entry as it exists in the image + SbeXipToc* iv_toc; + + /// The full relocatable PORE address + /// + /// All relocatable addresses are computed from the \a iv_linkAddress + /// stored in the header. For scalar and string data, this is the + /// relocatable address of the data. For address-only entries, this is + /// the indexed address itself. + uint64_t iv_address; + + /// A host pointer to the first byte of text or data within the image + /// + /// For scalar or string types this is a host pointer to the first byte of + /// the data. For code pointers (addresses) this is host pointer to the + /// first byte of code. Note that any use of this field requires the + /// caller to handle conversion of the data to host endian-ness if + /// required. Only 8-bit and string data can be used directly on all + /// hosts. + void* iv_imageData; + + /// The item name + /// + /// This is a pointer in host memory to a string that names the TOC entry + /// requested. This field is set to a pointer to the ID string of the TOC + /// entry inside the image. + char* iv_id; + + /// The data type, one of the SBE_XIP_* constants + uint8_t iv_type; + + /// The number of elements in a vector + /// + /// This field is set from the TOC entry when the TOC entry is + /// decoded. This value is stored as 1 for scalar declarations, and may be + /// set to 0 for vectors with large or undeclared sizes. Otherwise it is + /// used to bounds check indexed accesses. + uint8_t iv_elements; + +} SbeXipItem; + + +/// Prototype entry in the .halt section +/// +/// The .halt section is generated by the 'reqhalt' macro. This structure +/// associates the address of each halt with the string form of the FAPI +/// return code associated with the halt. The string form is used because the +/// FAPI error return code is not constant. The .halt section is 4-byte +/// aligned, and each address/string entry is always padded to a multiple of 4 +/// bytes. +/// +/// In the .halt section the \a iv_string may be any length, thus the size of +/// each actual record is variable (although guaranteed to always be a +/// multiple of 4 bytes). Although the C compiler might natuarlly align +/// instances of this structure on a 64-bit boundary, the APIs that allow +/// access to the .halt section assume that the underlying machine can do +/// non-aligned loads from a pointer to this structure. + +typedef struct { + + /// The 64-bit relocatable address of the halt + /// + /// This is the address found in the PC (Status Register bits 16:63) when + /// the PORE halts. The full 64-bit form is used rather than the simple + /// 32-bit offset to support merging SEEPROM and PIBMEM .halt sections in + /// the SEEPROM IPL images. + uint64_t iv_address; + + /// A C-prototype for a variable-length 0-terminated ASCII string + /// + /// This is a prototype only to simplify C programming. The actual string + /// may be any length. + char iv_string[4]; + +} SbeXipHalt; + + +/// Validate an SBE-XIP image +/// +/// \param[in] i_image A pointer to an SBE-XIP image in host memory. +/// +/// \param[in] i_size The putative size of the image +/// +/// This API should be called first by all applications that manipulate +/// SBE-XIP images in host memory. The magic number is validated, and +/// the image is checked for consistency of the section table and table of +/// contents. The \a iv_imageSize field of the header must also match the +/// provided \a i_size parameter. Validation does not modify the image. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_validate(void* i_image, const uint32_t i_size); + + +/// Normalize the SBE-XIP image +/// +/// \param[in] io_image A pointer to an SBE-XIP image in host memory. The +/// image is assumed to be consistent with the information contained in the +/// header regarding the presence of and sizes of all sections. +/// +/// SBE-XIP images must be normalized before any other APIs are allowed to +/// operate on the image. Since normalization modifies the image, an explicit +/// call to normalize the image is required. Briefly, normalization modifies +/// the TOC entries created by the final link to simplify search, updates, +/// modification and relocation of the image. Normalization is explained in +/// the written documentation of the SBE-XIP binary format. Normalization does +/// not modify the size of the image. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_normalize(void* io_image); + + +/// Return the size of an SBE-XIP image from the image header +/// +/// \param[in] i_image A pointer to an SBE-XIP image in host memory. The +/// image is assumed to be consistent with the information contained in the +/// header regarding the presence of and sizes of all sections. +/// +/// \param[out] o_size A pointer to a variable returned as the size of the +/// image in bytes, as recorded in the image header. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_image_size(void* i_image, uint32_t* o_size); + + +/// Locate a section table entry and translate into host format +/// +/// \param[in] i_image A pointer to an SBE-XIP image in host memory. +/// +/// \param[in] i_sectionId Identifies the section to be queried. See \ref +/// sbe_xip_sections. +/// +/// \param[out] o_hostSection Updated to contain the section table entry +/// translated to host byte order. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_get_section(const void* i_image, + const int i_sectionId, + SbeXipSection* o_hostSection); + + +/// Endian translation of an SbeXipHeader object +/// +/// \param[out] o_hostHeader The destination object. +/// +/// \param[in] i_imageHeader The source object. +/// +/// Translation of a SbeXipHeader includes translation of all data members +/// including traslation of the embedded section table. This translation +/// works even if \a o_src == \a o_dest, i.e., in the destructive case. +void +sbe_xip_translate_header(SbeXipHeader* o_hostHeader, + const SbeXipHeader* i_imageHeader); + + +/// Get scalar data from an SBE-XIP image +/// +/// \param[in] i_image A pointer to an SBE-XIP image in host memory. The +/// image is assumed to be consistent with the information contained in the +/// header regarding the presence of and sizes of all sections. The image is +/// also required to have been normalized. +/// +/// \param[in] i_id A pointer to a 0-terminated ASCII string naming the item +/// requested. +/// +/// \param[out] o_data A pointer to an 8-byte integer to receive the scalar +/// data. Assuming the item is located this variable is assigned by the call. +/// In the event of an error the final state of \a o_data is not specified. +/// +/// This API searches the SBE-XIP Table of Contents (TOC) for the item named +/// \a i_id, assigning \a o_data from the image if the item is found and is a +/// scalar value. Scalar values include 8- 32- and 64-bit integers and PORE +/// addresses. Image data smaller than 64 bits are extracted as unsigned +/// types, and it is the caller's responsibility to cast or convert the +/// returned data as appropriate. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_get_scalar(void *i_image, const char* i_id, uint64_t* o_data); + + +/// Get an integral element from a vector held in an SBE-XIP image +/// +/// \param[in] i_image A pointer to an SBE-XIP image in host memory. The +/// image is assumed to be consistent with the information contained in the +/// header regarding the presence of and sizes of all sections. The image is +/// also required to have been normalized. +/// +/// \param[in] i_id A pointer to a 0-terminated ASCII string naming the item +/// requested. +/// +/// \param[in] i_index The index of the vector element to return. +/// +/// \param[out] o_data A pointer to an 8-byte integer to receive the +/// data. Assuming the item is located this variable is assigned by the call. +/// In the event of an error the final state of \a o_data is not specified. +/// +/// This API searches the SBE-XIP Table of Contents (TOC) for the \a i_index +/// element of the item named \a i_id, assigning \a o_data from the image if +/// the item is found, is a vector of an integral type, and the \a i_index is +/// in bounds. Vector elements smaller than 64 bits are extracted as unsigned +/// types, and it is the caller's responsibility to cast or convert the +/// returned data as appropriate. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_get_element(void *i_image, + const char* i_id, + const uint32_t i_index, + uint64_t* o_data); + + +/// Get string data from an SBE-XIP image +/// +/// \param[in] i_image A pointer to an SBE-XIP image in host memory. The +/// image is assumed to be consistent with the information contained in the +/// header regarding the presence of and sizes of all sections. The image is +/// also required to have been normalized. +/// +/// \param[in] i_id A pointer to a 0-terminated ASCII string naming the item +/// requested. +/// +/// \param[out] o_data A pointer to a character pointer. Assuming the +/// item is located this variable is assigned by the call to point to the +/// string as it exists in the \a i_image. In the event of an error the final +/// state of \a o_data is not specified. +/// +/// This API searches the SBE-XIP Table of Contents (TOC) for the item named +/// \a i_id, assigning \a o_data if the item is found and is a string. It is +/// the caller's responsibility to copy the string from the \a i_image memory +/// space if necessary. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_get_string(void *i_image, const char* i_id, char** o_data); + + +/// Directly read 64-bit data from the image based on a PORE address +/// +/// \param[in] i_image A pointer to an SBE-XIP image in host memory. The +/// image is assumed to be consistent with the information contained in the +/// header regarding the presence of and sizes of all sections. +/// +/// \param[in] i_poreAddress A relocatable PORE address contained in the +/// image, presumably of an 8-byte data area. The \a i_poreAddress is +/// required to be 8-byte aligned, otherwise the SBE_XIP_ALIGNMENT_ERROR code +/// is returned. +/// +/// \param[out] o_data The 64 bit data in host format that was found at \a +/// i_poreAddress. +/// +/// This API is provided for applications that need to manipulate SBE-XIP +/// images in terms of their relocatable PORE addresses. The API checks that +/// the \a i_poreAddress is properly aligned and contained in the image, then +/// reads the contents of \a i_poreAddress into \a o_data, performing +/// image-to-host endianess conversion if required. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_read_uint64(const void *i_image, + const uint64_t i_poreAddress, + uint64_t* o_data); + + +/// Set scalar data in an SBE-XIP image +/// +/// \param[in,out] io_image A pointer to an SBE-XIP image in host memory. +/// The image is assumed to be consistent with the information contained in +/// the header regarding the presence of and sizes of all sections. The image +/// is also required to have been normalized. +/// +/// \param[in] i_id A pointer to a 0-terminated ASCII string naming the item +/// to be modified. +/// +/// \param[in] i_data The new scalar data. +/// +/// This API searches the SBE-XIP Table of Contents (TOC) for the item named +/// by \a i_id, updating the image from \a i_data if the item is found, has +/// a scalar type and can be modified. For this API the scalar types include +/// 8- 32- and 64-bit integers. Although PORE addresses are considered a +/// scalar type for sbe_xip_get_scalar(), PORE addresses can not be modified +/// by this API. The caller is responsible for ensuring that the \a i_data is +/// of the correct size for the underlying data element in the image. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_set_scalar(void* io_image, const char* i_id, const uint64_t i_data); + + +/// Set an integral element in a vector held in an SBE-XIP image +/// +/// \param[in] i_image A pointer to an SBE-XIP image in host memory. The +/// image is assumed to be consistent with the information contained in the +/// header regarding the presence of and sizes of all sections. The image is +/// also required to have been normalized. +/// +/// \param[in] i_id A pointer to a 0-terminated ASCII string naming the item +/// to be updated. +/// +/// \param[in] i_index The index of the vector element to update. +/// +/// \param[out] i_data The new vector element. +/// +/// This API searches the SBE-XIP Table of Contents (TOC) for the \a i_index +/// element of the item named \a i_id, update the image from \a i_data if the +/// item is found, is a vector of an integral type, and the \a i_index is in +/// bounds. The caller is responsible for ensuring that the \a i_data is of +/// the correct size for the underlying data element in the image. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_set_element(void *i_image, + const char* i_id, + const uint32_t i_index, + const uint64_t i_data); + + +/// Set string data in an SBE-XIP image +/// +/// \param[in] i_image A pointer to an SBE-XIP image in host memory. The +/// image is assumed to be consistent with the information contained in the +/// header regarding the presence of and sizes of all sections. The image is +/// also required to have been normalized. +/// +/// \param[in] i_id A pointer to a 0-terminated ASCII string naming the item +/// to be modified. +/// +/// \param[in] i_data A pointer to the new string data. +/// +/// This API searches the SBE-XIP Table of Contents (TOC) for the item named +/// \a i_id, which must be a string variable. If found, then the string data +/// in the image is overwritten with \a i_data. Strings are held 0-terminated +/// in the image, and the SBE-XIP format does not maintain a record of the +/// amount of memory allocated for an individual string. If a string is +/// overwritten by a shorter string then the 'excess' storage is effectively +/// lost. If the length of \a i_data is longer that the current strlen() of +/// the string data then \a i_data is silently truncated to the first +/// strlen(old_string) characters. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_set_string(void *io_image, const char* i_id, const char* i_data); + + +/// Directly write 64-bit data into the image based on a PORE address +/// +/// \param[in, out] io_image A pointer to an SBE-XIP image in host memory. The +/// image is assumed to be consistent with the information contained in the +/// header regarding the presence of and sizes of all sections. +/// +/// \param[in] i_poreAddress A relocatable PORE address contained in the +/// image, presumably of an 8-byte data area. The \a i_poreAddress is +/// required to be 8-byte aligned, otherwise the SBE_XIP_ALIGNMENT_ERROR code +/// is returned. +/// +/// \param[in] i_data The 64 bit data in host format to be written to \a +/// i_poreAddress. +/// +/// This API is provided for applications that need to manipulate SBE-XIP +/// images in terms of their relocatable PORE addresses. The API checks that +/// the \a i_poreAddress is properly aligned and contained in the image, then +/// updates the contents of \a i_poreAddress with \a i_data, performing +/// host-to-image endianess conversion if required. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_write_uint64(void *io_image, + const uint64_t i_poreAddress, + const uint64_t i_data); + + +/// Map over an SBE-XIP image Table of Contents +/// +/// \param[in,out] io_image A pointer to an SBE-XIP image in host memory. The +/// image is assumed to be consistent with the information contained in the +/// header regarding the presence of and sizes of all sections. The image is +/// also required to have been normalized. +/// +/// \param[in] i_fn A pointer to a function to call on each TOC entry. The +/// function has the prototype: +/// +/// \code +/// int (*i_fn)(void* io_image, +/// const SbeXipItem* i_item, +/// void* io_arg) +/// \endcode +/// +/// \param[in,out] io_arg The private argument of \a i_fn. +/// +/// This API iterates over each entry of the TOC, calling \a i_fn with +/// pointers to the image, an SbeXipItem* pointer, and a private argument. The +/// iteration terminates either when all TOC entries have been mapped, or \a +/// i_fn returns a non-zero code. +/// +/// \retval 0 Success; All TOC entries were mapped, including the case that +/// the .toc section is empty. +/// +/// \revtal non-0 May be either one of the SBE-XIP image error codes (see \ref +/// sbe_xip_image_errors), or a non-zero code from \a i_fn. Since the standard +/// SBE_XIP return codes are > 0, application-defined codes should be < 0. +int +sbe_xip_map_toc(void* io_image, + int (*i_fn)(void* io_image, + const SbeXipItem* i_item, + void* io_arg), + void* io_arg); + + +/// Find an SBE-XIP TOC entry +/// +/// \param[in] i_image A pointer to an SBE-XIP image in host memory. The +/// image is assumed to be consistent with the information contained in the +/// header regarding the presence of and sizes of all sections. The image is +/// also required to have been normalized. +/// +/// \param[in] i_id A 0-byte terminated ASCII string naming the item to be +/// searched for. +/// +/// \param[out] o_item If the search is successful, then the object +/// pointed to by \a o_item is filled in with the decoded form of the +/// TOC entry for \a i_id. If the API returns a non-0 error code then the +/// final state of the storage at \a o_item is undefined. This parameter may +/// be suppied as 0, in which case sbe_xip_find() serves as a simple predicate +/// on whether an item is indexded in the TOC. +/// +/// This API searches the TOC of a normalized SBE-XIP image for the item named +/// \a i_id, and if found, fills in the structure pointed to by \a +/// o_item with a decoded form of the TOC entry. If the item is not found, +/// the following two return codes may be considered non-error codes: +/// +/// - SBE_XIP_ITEM_NOT_FOUND : No TOC record for \a i_id was found. +/// +/// - SBE_XIP_DATA_NOT_PRESENT : The item appears in the TOC, however the +/// section containing the data is no longer present in the image. +/// +/// \note This API should not be used unless absolutely necessary. To obtain +/// data from the image or update data in the image use the sbe_xip_get_*() +/// and sbe_xip_set_*() APIs respectively whenever possible. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_find(void* i_image, + const char* i_id, + SbeXipItem* o_item); + + +/// Map over an SBE-XIP image .halt section +/// +/// \param[in,out] io_image A pointer to an SBE-XIP image in host memory. The +/// image is assumed to be consistent with the information contained in the +/// header regarding the presence of and sizes of all sections. +/// +/// \param[in] i_fn A pointer to a function to call on each entry in .halt. +/// The function has the prototype: +/// +/// \code +/// int (*i_fn)(void* io_image, +/// const uint64_t i_poreAddress, +/// const char* i_rcString, +/// void* io_arg) +/// +/// \param[in,out] io_arg The private argument of \a i_fn. +/// +/// This API iterates over each entry of the .halt section, calling \a i_fn +/// with each HALT address, the string form of the return code associated with +/// that HALT address, and a private argument. The iteration terminates either +/// when all .halt entries have been mapped, or \a i_fn returns a non-zero +/// code. The \a i_poreAddddress passed to \a i_fn is the full 48-bit +/// relocatable PORE address. +/// +/// \retval 0 Success, including the case that the image has no .halt section. +/// +/// \revtal non-0 May be either one of the SBE-XIP image error codes (see \ref +/// sbe_xip_image_errors), or any non-zero code from \a i_fn. Since the +/// standard SBE_XIP return codes are > 0, application-defined codes should be +/// < 0. +int +sbe_xip_map_halt(void* io_image, + int (*i_fn)(void* io_image, + const uint64_t i_poreAddress, + const char* i_rcString, + void* io_arg), + void* io_arg); + + +/// Get the string from of a HALT code from an SBE-XIP image .halt section +/// +/// \param[in,out] io_image A pointer to an SBE-XIP image in host memory. The +/// image is assumed to be consistent with the information contained in the +/// header regarding the presence of and sizes of all sections. +/// +/// \param[in] i_poreAddress This is the 48-bit address found in the PC when +/// the PORE halts. This address is actually 4 bytes beyond the actual HALT +/// instruction, however for simplicity this is the address used to index the +/// HALT. +/// +/// \param[out] o_rcString The caller provides the address of a string-pointer +/// variable which is updated with a pointer to the string form of the halt +/// code associated with \a i_poreAddress (assuming a successful completion). +/// +/// \retval 0 Success +/// +/// \retval SBE_XIP_ITEM_NOT_FOUND The \a i_poreAddress is not associated +/// with a halt code in .halt. +/// +/// \revtal Other See \ref sbe_xip_image_errors +int +sbe_xip_get_halt(void* io_image, + const uint64_t i_poreAdress, + const char** o_rcString); + + +/// Delete a section from an SBE-XIP image in host memory +/// +/// \param[in,out] i_image A pointer to an SBE-XIP image in host memory. The +/// image is assumed to be consistent with the information contained in the +/// header regarding the presence of and sizes of all sections. The image is +/// also required to have been normalized. +/// +/// \param[in] i_sectionId Identifies the section to be deleted. See \ref +/// sbe_xip_sections. +/// +/// This API effectively deletes a section from an SBE-XIP image held in host +/// memory. Unless the requested section \a i_section is already empty, only +/// the final (highest address offset) section of the image may be deleted. +/// Deleting the final section of the image means that the section size is set +/// to 0, and the size of the image recorded in the header is reduced by the +/// section size. This API does not check for or warn if other sections in +/// the image reference the deleted section. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_delete_section(void* io_image, const int i_sectionId); + + +/// Duplicate a section from an SBE-XIP image in host memory +/// +/// \param[in,out] i_image A pointer to an SBE-XIP image in host memory. The +/// image is assumed to be consistent with the information contained in the +/// header regarding the presence of and sizes of all sections. +/// +/// \param[in] i_sectionId Identifies the section to be duplicated. See \ref +/// sbe_xip_sections. +/// +/// \param[out] o_duplicate At exit, points to the newly allocated and +/// initialized duplicate of the given section. The caller is responsible for +/// free()-ing this memory when no longer required. +/// +/// \param[out] o_size At exit, contains the size (in bytes) of the duplicated +/// section. +/// +/// This API creates a bytewise duplicate of a non-empty section into newly +/// malloc()-ed memory. At exit \a o_duplicate points to the duplicate, and \i +/// o_size is set the the size of the duplicated section. The caller is +/// responsible for free()-ing the memory when no longer required. The +/// pointer at \o_duplicate is set to NULL (0) and teh \a o_size is set to 0 +/// in the event of any failure. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_duplicate_section(const void* i_image, + const int i_sectionId, + void** o_duplicate, + uint32_t* size); + + +/// Append binary data to an SBE-XIP image held in host memory +/// +/// \param[in,out] io_image A pointer to an SBE-XIP image in host memory. The +/// image is assumed to be consistent with the information contained in the +/// header regarding the presence of and sizes of all sections. The image is +/// also required to have been normalized. +/// +/// \param[in] i_sectionId Identifies the section to contain the new data. +/// +/// \param[in] i_data A pointer to the data to be appended to the image. If +/// this pointer is NULL (0), then the effect is as if \a i_data were a +/// pointer to an \a i_size array of 0 bytes. +/// +/// \param[in] i_size The size of the data to be appended in bytes. If \a +/// i_data is 0, then this is the number of bytes to clear. +/// +/// \param[in] i_allocation The size of the memory region containing the +/// image, measured from the first byte of the image. The call will fail if +/// appending the new data plus any alignment padding would overflow the +/// allocated memory. +/// +/// \param[out] o_sectionOffset If non-0 at entry, then the API updates the +/// location pointed to by \a o_sectionOffset with the offset of the first +/// byte of the appended data within the indicated section. +/// +/// This API copies data from \a i_data to the end of the indicated \a +/// i_section. The section \a i_section must either be empty, or must be the +/// final (highest address) section in the image. If the section is initially +/// empty and \a i_size is non-0 then the section is created at the end of the +/// image. The size of \a i_section and the size of the image are always +/// adjusted to reflect the newly added data. This is a simple binary copy +/// without any interpretation (e.g., endian-translation) of the copied data. +/// The caller is responsible for insuring that the host memory area +/// containing the SBE-XIP image is large enough to hold the newly appended +/// data without causing addressing errors or buffer overrun errors. +/// +/// The final parameter \a o_sectionOffset is optional, and may be passed as +/// NULL (0) if the application does not require the information. This return +/// value is provided to simplify typical use cases of this API: +/// +/// - A scan program is appended to the image, or a run-time data area is +/// allocated and cleared at the end of the image. +/// +/// - Pointer variables in the image are updated with PORE addresses obtained +/// via sbe_xip_section2pore(), or +/// other procedure code initializes a newly allocated and cleared data area +/// via host addresses obtained from sbe_xip_section2host(). +/// +/// Regarding alignment, note that the SBE-XIP format requires that sections +/// maintain an initial alignment that varies by section, and the API will +/// enforce these alignment constraints for all sections created by the API. +/// All alignment is relative to the first byte of the image (\a io_image) - +/// \e not to the current in-memory address of the image. By specification +/// SBE-XIP images must be loaded at a 4K alignment in order for PORE hardware +/// relocation to work, however the APIs don't require this 4K alignment for +/// in-memory manipulation of images. Images to be executed on PoreVe will +/// normally require at least 8-byte final aligment in order to guarantee that +/// the PoreVe can execute an 8-byte fetch or load/store of the final +/// doubleword. +/// +/// \note If the TOC section is modified then the image is marked as having an +/// unsorted TOC. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_append(void* io_image, + const int i_sectionId, + const void* i_data, + const uint32_t i_size, + const uint32_t i_allocation, + uint32_t* o_sectionOffset); + + +/// Convert an SBE-XIP section offset to a relocatable PORE address +/// +/// \param[in] i_image A pointer to an SBE-XIP image in host memory +/// +/// \param[in] i_sectionId A valid SBE-XIP section identifier; The section +/// must be non-empty. +/// +/// \param[in] i_offset An offset (in bytes) within the section. At least one +/// byte at \a i_offset must be currently allocated in the section. +/// +/// \param[in] o_poreAddress The equivalent relocatable PORE address is +/// returned via this pointer. Since valid PORE addresses are always either +/// 4-byte (code) or 8-byte (data) aligned, this API checks the aligment of +/// the translated address and returns SBE_XIP_ALIGNMENT_ERROR if the PORE +/// address is not at least 4-byte aligned. Note that the translated address +/// is still returned even if incorrectly aligned. +/// +/// This API is typically used to translate section offsets returned from +/// sbe_xip_append() into relocatable PORE addresses. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_section2pore(const void* i_image, + const int i_sectionId, + const uint32_t i_offset, + uint64_t* o_poreAddress); + + +/// Convert an SBE-XIP relocatable PORE address to a host memory address +/// +/// \param[in] i_image A pointer to an SBE-XIP image in host memory. +/// +/// \param[in] i_poreAddress A relocatable PORE address putatively addressing +/// relocatable memory contained in the image. +/// +/// \param[out] o_hostAddress The API updates the location pointed to by \a +/// o_hostAddress with the host address of the memory addressed by \a +/// i_poreAddress. In the event of an error (non-0 return code) the final +/// content of \a o_hostAddress is undefined. +/// +/// This API is typically used to translate relocatable PORE addresses stored +/// in the SBE-XIP image into the equivalent host address of the in-memory +/// image, allowing host-code to manipulate arbitrary data structures in the +/// image. If the \a i_poreAddress does not refer to memory within the image +/// (as determined by the link address and image size) then the +/// SBE_XIP_INVALID_ARGUMENT error code is returned. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_pore2host(const void* i_image, + const uint64_t i_poreAddress, + void** o_hostAddress); + + +/// Convert an SBE-XIP relocatable PORE address to section Id and offset +/// +/// \param[in] i_image A pointer to an SBE-XIP image in host memory. +/// +/// \param[in] i_poreAddress A relocatable PORE address putatively addressing +/// relocatable memory contained in the image. +/// +/// \param[out] o_section The API updates the location pointed to by \a +/// o_section with the section Id of the memory addressed by \a +/// i_poreAddress. In the event of an error (non-0 return code) the final +/// content of \a o_section is undefined. +/// +/// \param[out] o_offset The API updates the location pointed to by \a +/// o_offset with the byte offset of the memory addressed by \a i_poreAddress +/// within \a o_section. In the event of an error (non-0 return code) the +/// final content of \a o_offset is undefined. +/// +/// This API is typically used to translate relocatable PORE addresses stored +/// in the SBE-XIP image into the equivalent section + offset form, allowing +/// host-code to manipulate arbitrary data structures in the image. If the \a +/// i_poreAddress does not refer to memory within the image (as determined by +/// the link address and image size) then the SBE_XIP_INVALID_ARGUMENT error +/// code is returned. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_pore2section(const void* i_image, + const uint64_t i_poreAddress, + int* o_section, + uint32_t* o_offset); + + +/// Convert an in-memory SBE-XIP host address to a relocatable PORE address +/// +/// \param[in] i_image A pointer to an SBE-XIP image in host memory +/// +/// \param[in] i_hostAddress A host address addressing data within the image. +/// +/// \param[out] o_poreAddress The API updates the location pointed to by \a +/// o_poreAddress with the equivelent relocatable PORE address of the memory +/// addressed by i_hostAddress. Since valid PORE addresses are always either +/// 4-byte (code) or 8-byte (data) aligned, this API checks the aligment of +/// the translated address and returns SBE_XIP_ALIGNMENT_ERROR if the PORE +/// address is not at least 4-byte aligned. Note that the translated address +/// is still returned evn if incorrectly aligned. +/// +/// This API is provided as a convenient way to convert host memory addresses +/// for an in-memory SBE-XIP image into PORE addresses correctly relocated for +/// the image, for example to update pointer variables in the image. If the +/// \a i_hostAddress does not refer to memory within the image (as determined +/// by the image address and image size) then the SBE_XIP_INVALID_ARGUMENT +/// error code is returned. +/// +/// \retval 0 Success +/// +/// \retval non-0 See \ref sbe_xip_image_errors +int +sbe_xip_host2pore(const void* i_image, + void* i_hostAddress, + uint64_t* i_poreAddress); + + +/// \defgroup sbe_xip_image_errors Error codes from SBE-XIP image APIs +/// +/// @{ + +/// A putative SBE-XIP image does not have the correct magic number, or +/// contains some other major inconsistency. +#define SBE_XIP_IMAGE_ERROR 1 + +/// The TOC may be missing, partially present or may have an alignment problem. +#define SBE_XIP_TOC_ERROR 2 + +/// A named item was not found in the SBE-XIP TOC, or a putative HALT address +/// is not associated with a halt code in .halt. +#define SBE_XIP_ITEM_NOT_FOUND 3 + +/// A named item appears in the SBE-XIP TOC, but the data is not present in +/// the image. This error can occur if sections have been deleted from the +/// image. +#define SBE_XIP_DATA_NOT_PRESENT 4 + +/// A named item appears in the SBE-XIP TOC, but the data can not be +/// modified. This error will occur if an attempt is made to modify an +/// address-only entry. +#define SBE_XIP_CANT_MODIFY 5 + +/// A direct or implied argument is invalid, e.g. an illegal data type or +/// section identifier, or an address not contained within the image. +#define SBE_XIP_INVALID_ARGUMENT 6 + +/// A data type mismatch or an illegal type was specified or implied for an +/// operation. +#define SBE_XIP_TYPE_ERROR 8 + +/// A bug in an SBE-XIP image API +#define SBE_XIP_BUG 8 + +/// The image must first be normalized with sbe_xip_normalize(). +#define SBE_XIP_NOT_NORMALIZED 9 + +/// Attempt to delete a non-empty section that is not the final section of the +/// image, or an attempt to append data to a non-empty section that is not the +/// final section of the image, or an attempt to operate on an empty section +/// for those APIs that prohibit this. +#define SBE_XIP_SECTION_ERROR 10 + +/// An address translation API returned a PORE address that was not at least +/// 4-byte aligned, or alignment violations were observed by +/// sbe_xip_validate() or sbe_xip_append(). +#define SBE_XIP_ALIGNMENT_ERROR 11 + +/// An API that performs dynamic memory allocation was unable to allocate +/// memory. +#define SBE_XIP_NO_MEMORY 12 + +/// Attempt to get or set a vector element with an index that is outside of +/// the declared bounds of the vector. +#define SBE_XIP_BOUNDS_ERROR 13 + +/// Attempt to grow the image past its defined memory allocation +#define SBE_XIP_WOULD_OVERFLOW 14 + +/// Error associated with the disassembler occured. +#define SBE_XIP_DISASSEMBLER_ERROR 15 + +/// Applications can expand this macro to declare an array of string forms of +/// the error codes if desired. +#define SBE_XIP_ERROR_STRINGS(var) \ + const char* var[] = { \ + "Success", \ + "SBE_XIP_IMAGE_ERROR", \ + "SBE_XIP_TOC_ERROR", \ + "SBE_XIP_ITEM_NOT_FOUND", \ + "SBE_XIP_DATA_NOT_PRESENT", \ + "SBE_XIP_CANT_MODIFY", \ + "SBE_XIP_INVALID_ARGUMENT", \ + "SBE_XIP_TYPE_ERROR", \ + "SBE_XIP_BUG", \ + "SBE_XIP_NOT_NORMALIZED", \ + "SBE_XIP_SECTION_ERROR", \ + "SBE_XIP_ALIGNMENT_ERROR", \ + "SBE_XIP_NO_MEMORY", \ + "SBE_XIP_BOUNDS_ERROR", \ + "SBE_XIP_WOULD_OVERFLOW", \ + "SBE_XIP_DISASSEMBLER_ERROR", \ + } + +/// Applications can use this macro to safely index the array of error +/// strings. +#define SBE_XIP_ERROR_STRING(var, n) \ + ((((n) < 0) || ((n) > (int)(sizeof(var) / sizeof(char*)))) ? \ + "Bug : Invalid SBE-XIP error code" : var[n]) + +/// @} + +/// Disassembler error codes. +#define DIS_IMAGE_ERROR 1 +#define DIS_MEMORY_ERROR 2 +#define DIS_DISASM_ERROR 3 +#define DIS_RING_NAME_ADDR_MATCH_SUCCESS 4 +#define DIS_RING_NAME_ADDR_MATCH_FAILURE 5 +#define DIS_TOO_MANY_DISASM_WARNINGS 6 +#define DIS_DISASM_TROUBLES 7 + +#define DIS_ERROR_STRINGS(var) \ + const char* var[] = { \ + "Success", \ + "DIS_IMAGE_ERROR", \ + "DIS_MEMORY_ERROR", \ + "DIS_DISASM_ERROR", \ + "DIS_RING_NAME_ADDR_MATCH_SUCCESS", \ + "DIS_RING_NAME_ADDR_MATCH_FAILURE", \ + "DIS_TOO_MANY_DISASM_WARNINGS", \ + "DIS_DISASM_TROUBLES", \ + } + +#define DIS_ERROR_STRING(var, n) \ + ((((n) < 0) || ((n) > (int)(sizeof(var) / sizeof(char*)))) ? \ + "Bug : Invalid DIS error code" : var[n]) + +#if 0 +{ /* So __cplusplus doesn't mess w/auto-indent */ +#endif +#ifdef __cplusplus +} +#endif + +#endif // __ASSEMBLER__ + + +//////////////////////////////////////////////////////////////////////////// +// Assembler Definitions +//////////////////////////////////////////////////////////////////////////// + +#ifdef __ASSEMBLER__ + +/// Create an XIP TOC entry +/// +/// \param[in] index The string form of the \a index symbol is created and +/// linked from the TOC entry to allow external search procedures to locate +/// the \a address. +/// +/// \param[in] type One of the SBE_XIP_* type constants; See \ref +/// sbe_xip_toc_types. +/// +/// \param[in] address The address of the idexed code or data; This wlll +/// typically be a symbol. +/// +/// \param[in] elements <Optional> For vector types, number of elements in the +/// vector, which is limited to an 8-bit unsigned integer. This parameter +/// defaults to 1 which indicates a scalar type. Declaring a vector with 0 +/// elements disables bounds checking on vector accesses, and can be used if +/// very large or indeterminate sized vectors are required. The TOC format +/// does not support vectors of strings or addresses. +/// +/// The \c .xip_toc macro creates a XIP Table of Contents (TOC) structure in +/// the \c .toc section, as specified by the parameters. This macro is +/// typically not used directly in assembly code. Instead programmers should +/// use .xip_quad, .xip_quada, .xip_quadia, .xip_address, .xip_string or +/// .xip_cvs_revision. + + .macro .xip_toc, index:req, type:req, address:req, elements=1 + + .if (((\type) < 1) || ((\type) > SBE_XIP_MAX_TYPE_INDEX)) + .error ".xip_toc : Illegal type index" + .endif + + // First push into the .strings section to lay down the + // string form of the index name under a local label. + + .pushsection .strings +7667862: + .asciz "\index" + .popsection + + // Now the 12-byte TOC entry is created. Push into the .toc section + // and lay down the first 4 bytes which are always a pointer to the + // string just declared. The next 4 bytes are the address of the data + // (or the address itself in the case of address types). The final 4 + // bytes are the type, section (always 0 prior to normalization), + // number of elements, and a padding byte. + + .pushsection .toc + + .long 7667862b, (\address) + .byte (\type), 0, (\elements), 0 + + .popsection + + .endm + + +/// Allocate and initialize 64-bit global scalar or vector data and create the +/// TOC entry. +/// +/// \param[in] symbol The name of the scalar or vector; this name is also used +/// as the TOC index of the data. +/// +/// \param[in] init The initial value of (each element of) the data. +/// This is a 64-bit integer; To allocate address pointers use .xip_quada. +/// +/// \param[in] elements The number of 64-bit elements in the data structure, +/// defaulting to 1, with a maximum value of 255. +/// +/// \param[in] section The section where the data will be allocated, +/// default depends on the memory space + + .macro .xip_quad, symbol:req, init:req, elements=1, section + + ..xip_quad_helper .quad, \symbol, (\init), (\elements), \section + + .endm + + +/// Allocate and initialize 64-bit global scalar or vector data containing a +/// relocatable address in and create the TOC entry. +/// +/// \param[in] symbol The name of the scalar or vector; this name is also used +/// as the TOC index of the data. +/// +/// \param[in] init The initial value of (each element of) the data. This +/// will typically be a symbolic address. If the intention is to define an +/// address that will always be filled in later by image manipulation tools, +/// then use the .xip_quad macro with a 0 initial value. +/// +/// \param[in] elements The number of 64-bit elements in the data structure, +/// defaulting to 1, with a maximum value of 255. +/// +/// \param[in] section The section where the data will be allocated, +/// default depends on the memory space + + .macro .xip_quada, symbol:req, offset:req, elements=1, section + + ..xip_quad_helper .quada, \symbol, (\offset), (\elements), \section + + .endm + + +/// Helper for .xip_quad and .xip_quada + + .macro ..xip_quad_helper, directive, symbol, init, elements, section + + .if (((\elements) < 1) || ((\elements) > 255)) + .error "The number of vector elements must be in the range 1..255" + .endif + + ..xip_pushsection \section + .balign 8 + + .global \symbol +\symbol\(): + .rept (\elements) + \directive (\init) + .endr + + .popsection + + .xip_toc \symbol, SBE_XIP_UINT64, \symbol, (\elements) + + .endm + + +/// Allocate and initialize 64-bit global scalar or vector data containing +/// full 64-bit addresses and create a TOC entry +/// +/// \param[in] symbol The name of the scalar or vector; this name is also used +/// as the TOC index of the data. +/// +/// \param[in] space A valid PORE memory space descriptor +/// +/// \param[in] offset A 32-bit relocatable offset +/// +/// \param[in] elements The number of 64-bit elements in the data structure, +/// defaulting to 1, with a maximum value of 255. +/// +/// \param[in] section The section where the data will be allocated, +/// default depends on the memory space + + .macro .xip_quadia, symbol:req, space:req, offset:req, \ + elements=1, section + + .if (((\elements) < 1) || ((\elements) > 255)) + .error "The number of vector elements must be in the range 1..255" + .endif + + ..xip_pushsection \section + .balign 8 + + .global \symbol +\symbol\(): + .rept (\elements) + .quadia (\space), (\offset) + .endr + + .popsection + + .xip_toc \symbol, SBE_XIP_UINT64, \symbol, (\elements) + + .endm + +/// Default push into .ipl_data unless in an OCI space, then .data + + .macro ..xip_pushsection, section + + .ifnb \section + .pushsection \section + .else + .if (_PGAS_DEFAULT_SPACE == PORE_SPACE_OCI) + .pushsection .data + .else + .pushsection .ipl_data + .endif + .endif + + .balign 8 + + .endm + +/// Allocate and initialize a string in .strings +/// +/// \param[in] index The string will be stored in the TOC using this index +/// symbol. +/// +/// \param[in] string The string to be allocated in .strings. String space is +/// fixed once allocated. Strings designed to be overwritten by external tools +/// should be allocated to be as long as eventually needed (e.g., by a string +/// of blanks.) + + .macro .xip_string, index:req, string:req + + .pushsection .strings +7874647: + .asciz "\string" + .popsection + + .xip_toc \index, SBE_XIP_STRING, 7874647b + + .endm + + +/// Allocate and initialize a CVS Revison string in .strings +/// +/// \param[in] index The string will be stored in the TOC using this index +/// symbol. +/// +/// \param[in] string A CVS revision string to be allocated in .strings. CVS +/// revision strings are formatted by stripping out and only storing the +/// actual revision number : +/// +/// \code +/// "$Revision <n>.<m> $" -> "<n>.<m>" +/// \endcode + + + .macro .xip_cvs_revision, index:req, string:req + + .pushsection .strings +7874647: + ..cvs_revision_string "\string" + .popsection + + .xip_toc \index, SBE_XIP_STRING, 7874647b + + .endm + + +/// Shorthand to create a TOC entry for an address +/// +/// \param[in] index The symbol will be indexed as this name +/// +/// \param[in] symbol <Optional> The symbol to index; by default the same as +/// the index. + + .macro .xip_address, index:req, symbol + + .ifb \symbol + .xip_toc \index, SBE_XIP_ADDRESS, \index + .else + .xip_toc \index, SBE_XIP_ADDRESS, \symbol + .endif + + .endm + + +/// Edit and allocate a CVS revision string +/// +/// CVS revision strings are formatted by stripping out and only storing the +/// actual revision number : +/// \code +/// "$Revision <n>.<m> $" -> "<n>.<m>" +/// \endcode + + .macro ..cvs_revision_string, rev:req + .irpc c, \rev + .ifnc "\c", "$" + .ifnc "\c", "R" + .ifnc "\c", "e" + .ifnc "\c", "v" + .ifnc "\c", "i" + .ifnc "\c", "s" + .ifnc "\c", "i" + .ifnc "\c", "o" + .ifnc "\c", "n" + .ifnc "\c", ":" + .ifnc "\c", " " + .ascii "\c" + .endif + .endif + .endif + .endif + .endif + .endif + .endif + .endif + .endif + .endif + .endif + .endr + .byte 0 + .endm + +#endif // __ASSEMBLER__ + +#endif // __SBE_XIP_TOC_H diff --git a/src/usr/hwpf/makefile b/src/usr/hwpf/makefile index ad020ada0..b2fae34c2 100644 --- a/src/usr/hwpf/makefile +++ b/src/usr/hwpf/makefile @@ -1,11 +1,11 @@ -# IBM_PROLOG_BEGIN_TAG +# IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # $Source: src/usr/hwpf/makefile $ # # IBM CONFIDENTIAL # -# COPYRIGHT International Business Machines Corp. 2011 +# COPYRIGHT International Business Machines Corp. 2011-2012 # # p1 # @@ -19,7 +19,7 @@ # # Origin: 30 # -# IBM_PROLOG_END +# IBM_PROLOG_END_TAG ROOTPATH = ../../.. SUBDIRS = fapi.d hwp.d plat.d test.d @@ -36,7 +36,9 @@ HWP_ERROR_XML_FILES = hwp/fapiHwpErrorInfo.xml \ hwp/dimm_errors.xml \ hwp/dram_training/memory_errors.xml \ hwp/start_clocks_on_nest_chiplets/proc_start_clocks_chiplets/proc_start_clocks_chiplets_errors.xml \ - hwp/edi_ei_initialization/proc_fab_iovalid/proc_fab_smp_errors.xml + hwp/edi_ei_initialization/proc_fab_iovalid/proc_fab_smp_errors.xml \ + hwp/build_winkle_images/proc_slw_build/proc_slw_build_errors.xml + HWP_ATTR_XML_FILES = hwp/memory_attributes.xml \ hwp/L2_L3_attributes.xml \ |