From ba424009d90cd7dc88abe948ba12f0a7720ec40c Mon Sep 17 00:00:00 2001 From: Derk Rembold Date: Tue, 28 Apr 2015 12:41:10 +0200 Subject: sbe_xip_tool, compiled with fapi2 inclusion updated Makefile because of Gregs changes recently. removed uneeded files. built in Greg's review comments Change-Id: I5a33599c2c098f8f0a5ef70ebb51b183a2e695d5 Reviewed-on: http://gfw160.aus.stglabs.ibm.com:8080/gerrit/17481 Reviewed-by: Derk Rembold Tested-by: Derk Rembold --- tools/image/Makefile | 124 +++ tools/image/p9_image_help_base.H | 95 ++ tools/image/p9_ring_identification.H | 41 + tools/image/p9_ring_identification.c | 122 ++ tools/image/p9_scan_compression.H | 345 ++++++ tools/image/ppeSetFixed.pl | 192 ++++ tools/image/sbe_default_tool.c | 286 +++++ tools/image/sbe_xip_tool.c | 2014 ++++++++++++++++++++++++++++++++++ 8 files changed, 3219 insertions(+) create mode 100644 tools/image/Makefile create mode 100644 tools/image/p9_image_help_base.H create mode 100644 tools/image/p9_ring_identification.H create mode 100644 tools/image/p9_ring_identification.c create mode 100644 tools/image/p9_scan_compression.H create mode 100644 tools/image/ppeSetFixed.pl create mode 100644 tools/image/sbe_default_tool.c create mode 100644 tools/image/sbe_xip_tool.c (limited to 'tools') diff --git a/tools/image/Makefile b/tools/image/Makefile new file mode 100644 index 00000000..d5991d5e --- /dev/null +++ b/tools/image/Makefile @@ -0,0 +1,124 @@ +############################################################################ + +# Makefile for image tools +# works on X86 Linux hosts. + +# Make targets: + +# all : +# +# utilities : Build utility programs and procedures +# +# clean : Removes the bin/ directory and all symbolic links +# + +############################################################################ + + +ifeq ($(CTEPATH),) +$(warning CTEPATH not defined; defaulting to awd) +CTEPATH = /afs/awd/projects/cte +endif + + +# Are we setup for eCMD, if so let's get our eCMD Release from there +ifneq ($(strip $(ECMD_RELEASE)),) + ECMD_RELEASE := $(shell ecmdVersion full) + # Make sure we got a valid version back + ifeq ($(findstring ver,$(ECMD_RELEASE)),) + ECMD_RELEASE := rel + endif +else + # If not setup for eCMD, default to rel + ECMD_RELEASE := rel +endif + + +# Ok, now set our eCMD Path, if not set already +ifeq ($(strip $(ECMD_PATH)),) + ECMD_PATH := ${CTEPATH}/tools/ecmd/${ECMD_RELEASE}/ +endif + +ifeq ($(strip $(ECMD_PLUGIN)),cro) +# Cronus plugin specific setup + CRONUS_PATH := $(shell echo ${ECMD_EXE} | sed -n 's|\([a-zA-Z0-9]*\)\(_*\)\([a-zA-Z0-9]*\)_x86\.exe|prcd_d|p') + ifeq ($(strip $(CRONUS_PATH)),) + $(error "Error determining CRONUS_PATH from env!") + endif +endif + +# We need common up-to-date headers for FAPI - currently using these. +FAPI = $(ECMD_PATH)ext/fapi + +# Locations of required headers. +INCLUDES += -I. -I../../ -I../../utils +INCLUDES += -I ../../sbe/image/ +INCLUDES += -I ../../sbe/sbefw/ +INCLUDES += -I ../../sbe/plat/include +INCLUDES += -I ../../hwpf/plat/include/ +INCLUDES += -I ../../pk/ppe42/ +INCLUDES += -I ../../pk/kernel/ +INCLUDES += -I ../../pk/std/ +INCLUDES += -I ../../pk/trace/ +INCLUDES += -I ../../tools/ppetracepp/ +INCLUDES += -I /afs/apd/u/rembold/ekb/hwpf/fapi2/include + +INCLUDES += -I$(CRONUS_PATH) +INCLUDES += -I$(ECMD_PATH)/capi +INCLUDES += -I$(FAPI)/capi + +# Under Linux the scheme is to use a common compiler to create procedures. +# However, the common compiler can be VERY slow, so if the system compiler is +# also 4.1.2 we're using that one instead. Also, the Linux FAPI libraries we +# link with are 32-bit only so we need to force 32-bit mode. + +ifeq ($(wildcard /etc/ldap.conf), ) + GSACELL = ausgsa +else + GSACELL = $(shell cat /etc/ldap.conf | grep "host " | \ + cut -d" " -f2 | cut -d. -f1) +endif + +GCC-RELEASE = 4.8.2 +GCC-VERSION = $(shell gcc -v 2>&1 | grep "$(GCC-RELEASE)") + +ifeq ($(GCC-VERSION),) +$(error wrong compiler version. Use $(GCC-RELEASE) compiler. Try to execute scl enable devtoolset-2 bash first) +else +CC = gcc +CXX = g++ +endif + +#UTILITIES-SOURCES += ../../sbe/image/sbe_xip_image.c +UTILITIES-SOURCES = sbe_xip_tool.c sbe_default_tool.c + +UTILITIES = sbe_xip_tool sbe_default_tool + +# Utility targets +UTILITIES-OBJc = $(patsubst %.c,bin/%.o,$(UTILITIES-SOURCES)) +UTILITIES-OBJECTS += $(patsubst %.C,bin/%.o,$(UTILITIES-OBJc)) +UTILITIES-DEPENDENCIES = $(patsubst %.o,%.d,$(UTILITIES-OBJECTS)) +UTILITIES-EXECUTABLES = $(patsubst %,bin/%,$(UTILITIES)) + + +.PHONY : utilities +utilities: $(UTILITIES-EXECUTABLES) + +bin/%.o: %.c + $(CXX) -std=c++11 $(INCLUDES) $(CXXFLAGS) -DDEBUG_SBE_XIP_IMAGE=1 -DFAPI2_NO_FFDC -c -o $@ $< + +bin/sbe_xip_image.o: ../../sbe/image/sbe_xip_image.c + $(CXX) -std=c++11 $(INCLUDES) $(CXXFLAGS) -DDEBUG_SBE_XIP_IMAGE=1 -DFAPI2_NO_FFDC -c -o $@ $< + +bin/sbe_xip_tool: bin/sbe_xip_image.o bin/p9_ring_identification.o bin/sbe_xip_tool.o + $(CXX) $(CXXFLAGS) ${INCLUDES} -o $@ $^ + ln -sf bin/sbe_xip_tool sbe_xip_tool + +bin/sbe_default_tool: bin/sbe_xip_image.o bin/sbe_default_tool.o + $(CXX) $(CXXFLAGS) ${INCLUDES} -o $@ $^ + ln -sf bin/sbe_default_tool sbe_default_tool + +clean: + rm sbe_xip_tool sbe_default_tool + rm -rf bin + mkdir -p bin \ No newline at end of file diff --git a/tools/image/p9_image_help_base.H b/tools/image/p9_image_help_base.H new file mode 100644 index 00000000..9d13b2f4 --- /dev/null +++ b/tools/image/p9_image_help_base.H @@ -0,0 +1,95 @@ +#ifndef _P9_IMAGE_HELP_BASE_H_ +#define _P9_IMAGE_HELP_BASE_H_ + +#include + +// +// Various image/ring buffer sizes. Must be used by all users (VBU, FSP, HB, HBI, Cronus) +// +const uint32_t MAX_REF_IMAGE_SIZE = 5000000; // Max reference image size. +const uint32_t FIXED_SEEPROM_WORK_SPACE= 128*1024; // Max work space for Seeprom img. +const uint32_t MAX_SEEPROM_IMAGE_SIZE = 56*1024; // Max Seeprom image size. +const uint32_t FIXED_RING_BUF_SIZE = 60000; // Fixed ring buf size for _fixed. + +const uint8_t MAX_VPD_TYPES = 2; // #G and #R, so far. +#define CHIPLET_ID_MIN 0x00 +#define CHIPLET_ID_MAX 0x1F +#define CHIPLET_ID_EX_MIN 0x10 +#define CHIPLET_ID_EX_MAX 0x1F +const uint8_t MAX_CHIPLETS = CHIPLET_ID_MAX-CHIPLET_ID_MIN+1; +const uint32_t ASM_RS4_LAUNCH_BUF_SIZE = 24; // Byte size of RS4 launch buffer. +const uint32_t WF_ENCAP_SIZE = 400; // Byte size of WF encapsulation. + // (Actually, only 304B but may change.) +const uint32_t WF_WORST_CASE_SIZE_FAC = 4; // WC WF size = 3x ring length. + // (Assumes 12B per write.) + // (4x w/waits instructions.) +const uint32_t LISTING_STRING_SIZE = 256; +const uint64_t MAX_UINT64_T = (uint64_t)0xFFFFFFFF<<32 | (uint64_t)0xFFFFFFFF; + +const uint8_t RING_SECTION_ID[] = { + SBE_XIP_SECTION_RINGS, + SBE_XIP_SECTION_DCRINGS, +}; +const uint8_t RING_SECTION_ID_SIZE = sizeof(RING_SECTION_ID) / sizeof(RING_SECTION_ID[0]); + +#ifdef __cplusplus +extern "C" { +#endif + +// Base (shared) ring layout for both RS4 and Wiggle-flip layouts. +typedef struct { + uint64_t entryOffset; + uint64_t backItemPtr; + uint32_t sizeOfThis; + uint32_t sizeOfMeta; // Exact size of meta data. Arbitrary size. Not null terminated. +} BaseRingLayout; + +// RS4 specific layout. +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; +} Rs4RingLayout; + +// PairingInfo is used for pairing, or matching, a back pointer address of a +// ring block with its corresponding TOC name. +typedef struct { + uint64_t address; // (in) Holds HOMER backPtr addr of the ring + uint8_t vectorpos; // (in) Vector position of fwdPtr [0;31] + // max=0 for most VPD rings + // max=1 for all non-VPD rings + // max=1 for perv_ VPD rings + // max=15 for most VPD ex_ rings + // max=31 for 16 ex_ chiplets with override + char *name; // (out) TOC name + uint8_t isvpd; // (out) 0: Non-VPD ring 1: VPD ring + uint8_t overridable; // (out) 0: No (most VPD rings) 1: Yes (all non-VPD rings) + uint8_t override; // (out) 0: base 1: override +} PairingInfo; + + +/// +/// **************************************************************************** +/// Function declares. +/// **************************************************************************** +/// +int over_write_ring_data_in_image( void *io_image, + const char *i_ringName, + const void *i_ringData, // WF or RS4 + const uint32_t i_sizeRingData, // Byte size + const uint8_t i_idxVector, + const uint8_t i_override, + const uint8_t i_overridable ); + + +#ifdef __cplusplus +} +#endif + +#endif //_P8_IMAGE_HELP_BASE_H_ diff --git a/tools/image/p9_ring_identification.H b/tools/image/p9_ring_identification.H new file mode 100644 index 00000000..e6ab8745 --- /dev/null +++ b/tools/image/p9_ring_identification.H @@ -0,0 +1,41 @@ +#ifndef _P9_RING_IDENT_H_ +#define _P9_RING_IDENT_H_ +#include +#include +#include +#include + + +// Ring ID list structure. +typedef struct { + const char *ringName; + uint8_t ringId; + uint8_t chipIdMin; // the min chipletId + uint8_t chipIdMax; // the max chipletId + const char *ringNameImg; // Ring name in image: ringName + "_ring" + uint8_t vpdKeyword; + uint8_t bWcSpace; // 0: fitted 1: worst-case space (3 x ring length) +} RingIdList; + +extern const RingIdList RING_ID_LIST_PG[], RING_ID_LIST_PR[]; +extern const uint32_t RING_ID_LIST_PG_SIZE, RING_ID_LIST_PR_SIZE; +extern const RingIdList RING_ID_LIST[]; +extern const uint32_t RING_ID_LIST_SIZE; + +// Enumerated VPD keyword values. +// Note! This is DIFFERENT from the MvpdKeyword list in fapiMvpdAccess.H which +// can't be used in this file since it's not, per se, a fapi file. So +// these values need to be translated in xip_customize when passing the +// mvpdKeyword to getMvpdRing(); +enum VpdKeyword { + VPD_KEYWORD_PDG, + VPD_KEYWORD_PDR, + NUM_OF_VPD_TYPES +}; + +int get_vpd_ring_list_entry(const char *i_ringName, + const uint8_t i_ringId, + RingIdList **i_ringIdList); + + +#endif diff --git a/tools/image/p9_ring_identification.c b/tools/image/p9_ring_identification.c new file mode 100644 index 00000000..0ee5797a --- /dev/null +++ b/tools/image/p9_ring_identification.c @@ -0,0 +1,122 @@ +#include + +const RingIdList RING_ID_LIST_PG[] = { + /* ringName ringId chipletId ringNameImg mvpdKeyword wc */ + /* min max */ + {"ab_gptr_ab", 0xA0, 0x08, 0x08, "ab_gptr_ab_ring", VPD_KEYWORD_PDG, 0}, + {"ab_gptr_ioa", 0xA1, 0x08, 0x08, "ab_gptr_ioa_ring", VPD_KEYWORD_PDG, 0}, + {"ab_gptr_perv", 0xA2, 0x08, 0x08, "ab_gptr_perv_ring", VPD_KEYWORD_PDG, 0}, + {"ab_gptr_pll", 0xA3, 0x08, 0x08, "ab_gptr_pll_ring", VPD_KEYWORD_PDG, 0}, + {"ab_time", 0xA4, 0x08, 0x08, "ab_time_ring", VPD_KEYWORD_PDG, 0}, + {"ex_gptr_core", 0xA5, 0xFF, 0xFF, "ex_gptr_core_ring", VPD_KEYWORD_PDG, 0}, //Chip specific + {"ex_gptr_dpll", 0xA6, 0xFF, 0xFF, "ex_gptr_dpll_ring", VPD_KEYWORD_PDG, 0}, //Chip specific + {"ex_gptr_l2", 0xA7, 0xFF, 0xFF, "ex_gptr_l2_ring", VPD_KEYWORD_PDG, 0}, //Chip specific + {"ex_gptr_l3", 0xA8, 0xFF, 0xFF, "ex_gptr_l3_ring", VPD_KEYWORD_PDG, 0}, //Chip specific + {"ex_gptr_l3refr", 0xA9, 0xFF, 0xFF, "ex_gptr_l3refr_ring", VPD_KEYWORD_PDG, 0}, //Chip specific + {"ex_gptr_perv", 0xAA, 0xFF, 0xFF, "ex_gptr_perv_ring", VPD_KEYWORD_PDG, 0}, //Chip specific + {"ex_time_core", 0xAB, 0x10, 0x1F, "ex_time_core_ring", VPD_KEYWORD_PDG, 0}, //Chiplet specfc + {"ex_time_eco", 0xAC, 0x10, 0x1F, "ex_time_eco_ring", VPD_KEYWORD_PDG, 0}, //Chiplet specfc + {"pb_gptr_dmipll", 0xAD, 0x02, 0x02, "pb_gptr_dmipll_ring", VPD_KEYWORD_PDG, 0}, + {"pb_gptr_mcr", 0xAE, 0x02, 0x02, "pb_gptr_mcr_ring", VPD_KEYWORD_PDG, 0}, + {"pb_gptr_nest", 0xAF, 0x02, 0x02, "pb_gptr_nest_ring", VPD_KEYWORD_PDG, 0}, + {"pb_gptr_nx", 0xB0, 0x02, 0x02, "pb_gptr_nx_ring", VPD_KEYWORD_PDG, 0}, + {"pb_gptr_pcis", 0xB1, 0x02, 0x02, "pb_gptr_pcis_ring", VPD_KEYWORD_PDG, 0}, + {"pb_gptr_perv", 0xB2, 0x02, 0x02, "pb_gptr_perv_ring", VPD_KEYWORD_PDG, 0}, + {"pb_time", 0xB3, 0x02, 0x02, "pb_time_ring", VPD_KEYWORD_PDG, 0}, + {"pb_time_mcr", 0xB4, 0x02, 0x02, "pb_time_mcr_ring", VPD_KEYWORD_PDG, 0}, + {"pb_time_nx", 0xB5, 0x02, 0x02, "pb_time_nx_ring", VPD_KEYWORD_PDG, 0}, + {"pci_gptr_iopci", 0xB6, 0x09, 0x09, "pci_gptr_iopci_ring", VPD_KEYWORD_PDG, 0}, + {"pci_gptr_pbf", 0xB7, 0x09, 0x09, "pci_gptr_pbf_ring", VPD_KEYWORD_PDG, 0}, + {"pci_gptr_pci0", 0xB8, 0x09, 0x09, "pci_gptr_pci0_ring", VPD_KEYWORD_PDG, 0}, + {"pci_gptr_pci1", 0xB9, 0x09, 0x09, "pci_gptr_pci1_ring", VPD_KEYWORD_PDG, 0}, + {"pci_gptr_pci2", 0xBA, 0x09, 0x09, "pci_gptr_pci2_ring", VPD_KEYWORD_PDG, 0}, + {"pci_gptr_perv", 0xBB, 0x09, 0x09, "pci_gptr_perv_ring", VPD_KEYWORD_PDG, 0}, + {"pci_gptr_pll", 0xBC, 0x09, 0x09, "pci_gptr_pll_ring", VPD_KEYWORD_PDG, 0}, + {"pci_time", 0xBD, 0x09, 0x09, "pci_time_ring", VPD_KEYWORD_PDG, 0}, + {"perv_gptr_net", 0xBE, 0x00, 0x00, "perv_gptr_net_ring", VPD_KEYWORD_PDG, 0}, + {"perv_gptr_occ", 0xBF, 0x00, 0x00, "perv_gptr_occ_ring", VPD_KEYWORD_PDG, 0}, + {"perv_gptr_perv", 0xC0, 0x00, 0x00, "perv_gptr_perv_ring", VPD_KEYWORD_PDG, 0}, + {"perv_gptr_pib", 0xC1, 0x00, 0x00, "perv_gptr_pib_ring", VPD_KEYWORD_PDG, 0}, + {"perv_gptr_pll", 0xC2, 0x00, 0x00, "perv_gptr_pll_ring", VPD_KEYWORD_PDG, 0}, + {"perv_time", 0xC3, 0x00, 0x00, "perv_time_ring", VPD_KEYWORD_PDG, 0}, + {"xb_gptr_iopci", 0xC4, 0x04, 0x04, "xb_gptr_iopci_ring", VPD_KEYWORD_PDG, 0}, + {"xb_gptr_iox", 0xC5, 0x04, 0x04, "xb_gptr_iox_ring", VPD_KEYWORD_PDG, 0}, + {"xb_gptr_pben", 0xC6, 0x04, 0x04, "xb_gptr_pben_ring", VPD_KEYWORD_PDG, 0}, + {"xb_gptr_perv", 0xC7, 0x04, 0x04, "xb_gptr_perv_ring", VPD_KEYWORD_PDG, 0}, + {"xb_time", 0xC8, 0x04, 0x04, "xb_time_ring", VPD_KEYWORD_PDG, 0}, + {"pb_gptr_mcl", 0xC9, 0x02, 0x02, "pb_gptr_mcl_ring", VPD_KEYWORD_PDG, 0}, + {"pb_time_mcl", 0xCA, 0x02, 0x02, "pb_time_mcl_ring", VPD_KEYWORD_PDG, 0}, +}; + +const RingIdList RING_ID_LIST_PR[] = { + /* ringName ringId chipIdMin chipIdMax ringNameImg mvpdKeyword */ + {"ab_repr", 0xE0, 0x08, 0x08, "ab_repr_ring", VPD_KEYWORD_PDR, 0}, + {"ex_repr_core", 0xE1, 0x10, 0x1F, "ex_repr_core_ring", VPD_KEYWORD_PDR, 1}, + {"ex_repr_eco", 0xE2, 0x10, 0x1F, "ex_repr_eco_ring", VPD_KEYWORD_PDR, 1}, + {"pb_repr", 0xE3, 0x02, 0x02, "pb_repr_ring", VPD_KEYWORD_PDR, 0}, + {"pb_repr_mcr", 0xE4, 0x02, 0x02, "pb_repr_mcr_ring", VPD_KEYWORD_PDR, 0}, + {"pb_repr_nx", 0xE5, 0x02, 0x02, "pb_repr_nx_ring", VPD_KEYWORD_PDR, 0}, + {"pci_repr", 0xE6, 0x09, 0x09, "pci_repr_ring", VPD_KEYWORD_PDR, 0}, + {"perv_repr", 0xE7, 0x00, 0x00, "perv_repr_ring", VPD_KEYWORD_PDR, 0}, + {"perv_repr_net", 0xE8, 0x00, 0x00, "perv_repr_net_ring", VPD_KEYWORD_PDR, 0}, + {"perv_repr_pib", 0xE9, 0x00, 0x00, "perv_repr_pib_ring", VPD_KEYWORD_PDR, 0}, + {"xb_repr", 0xEA, 0x04, 0x04, "xb_repr_ring", VPD_KEYWORD_PDR, 0}, + {"pb_repr_mcl", 0xEB, 0x02, 0x02, "pb_repr_mcl_ring", VPD_KEYWORD_PDR, 0}, +}; + +const uint32_t RING_ID_LIST_PG_SIZE = sizeof(RING_ID_LIST_PG)/sizeof(RING_ID_LIST_PG[0]); +const uint32_t RING_ID_LIST_PR_SIZE = sizeof(RING_ID_LIST_PR)/sizeof(RING_ID_LIST_PR[0]); + +// get_vpd_ring_list_entry() retrieves the MVPD list entry based on either a ringName +// or a ringId. If both are supplied, only the ringName is used. If ringName==NULL, +// then the ringId is used. A pointer to the RingIdList is returned. +int get_vpd_ring_list_entry(const char *i_ringName, + const uint8_t i_ringId, + RingIdList **i_ringIdList) +{ + int rc=0, NOT_FOUND=1, FOUND=0; + uint8_t iVpdType; + uint8_t iRing; + RingIdList *ring_id_list=NULL; + uint8_t ring_id_list_size; + + rc = NOT_FOUND; + for (iVpdType=0; iVpdTyperingName, i_ringName)==0 || + strcmp((ring_id_list+iRing)->ringNameImg,i_ringName)==0 ) { + *i_ringIdList = ring_id_list+iRing; + return FOUND; + } + } + } + else { + // Search for ringId match (since ringName was not supplied). + for (iRing=0; iRingringId==i_ringId) { + *i_ringIdList = ring_id_list+iRing; + return FOUND; + } + } + } + + } + return rc; +} + + + + diff --git a/tools/image/p9_scan_compression.H b/tools/image/p9_scan_compression.H new file mode 100644 index 00000000..2f1e285d --- /dev/null +++ b/tools/image/p9_scan_compression.H @@ -0,0 +1,345 @@ +#ifndef __P9_SCAN_COMPRESSION_H__ +#define __P9_SCAN_COMPRESSION_H__ + +/// This header declares and documents the entry points defined in +/// p9_scan_compression.C. Some constants are also required by the scan +/// decompression HOMER assembly procedures. + +#include "fapi_sbe_common.H" + +#ifndef __ASSEMBLER__ + +#include + +/// 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 - The ring ID uniquely identifying the repair ring name. +/// +/// 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 HOMER 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; + + /// Ring ID uniquely identifying the repair name. (See the list of ring + /// name vs ring IDs in p8_ring_identification.c). + uint8_t iv_ringId; + + /// 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[in,out] io_data This is a pointer to a memory area which must be +/// large enough to hold the worst-case result of compressing \a i_string (see +/// below). 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[in] i_dataSize The size of \a io_data in bytes. +/// +/// \param[out] o_imageSize The effective size of the entire compressed scan +/// data structure (header + compressed data) created in \a io_data, in bytes. +/// This value will always be a multiple of 8. +/// +/// \param[in] i_string The string to compress. Scan data to compress is +/// left-justified in this input string. +/// +/// \param[in] 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[in] 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[in] i_ringId The ring ID that uniquely identifies the ring name of +/// a repair ring. (See p8_ring_identification.c for more info.) +/// +/// \param[in] i_chipletId The 7-bit value for the iv_chipletId field of the +/// CompressedScanData. +/// +/// \param[in] 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. +/// +/// This API is required for integration with PHYP which does not support +/// malloc(). Applications in environments supporting malloc() can use +/// rs4_compress() instead. +/// +/// 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 require this worst-case amount of memory including the header and +/// any rounding required to guarantee that the data size is a multiple of 8 +/// bytes. The final image size is also rounded up to a multiple of 8 bytes. +/// If the \a i_dataSize is less than this amount (based on \a i_length) the +/// call will fail. +/// +/// \returns See \ref scan_compression_codes +int +_rs4_compress(CompressedScanData* io_data, + uint32_t i_dataSize, + uint32_t* o_imageSize, + const uint8_t* i_string, + const uint32_t i_length, + const uint64_t i_scanSelect, + const uint8_t i_ringId, + const uint8_t i_chipletId, + const uint8_t i_flushOptimization); + + +/// Compress a scan string using the RS4 compression algorithm +/// +/// \param[out] 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[out] 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[in] i_string The string to compress. Scan data to compress is +/// left-justified in this input string. +/// +/// \param[in] 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[in] 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[in] i_ringId The ring ID that uniquely identifies the ring name of +/// a repair ring. (See p8_ring_identification.c for more info.) +/// +/// \param[in] i_chipletId The 7-bit value for the iv_chipletId field of the +/// CompressedScanData. +/// +/// \param[in] 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_ringId, + const uint8_t i_chipletId, + const uint8_t i_flushOptimization); + + +/// Decompress a scan string compressed using the RS4 compression algorithm +/// +/// \param[in,out] io_string A caller-supplied data area to contain the +/// decompressed string. The \a i_stringSize must be large enough to contain +/// the decompressed string, which is the size of the original string in bits +/// rounded up to the nearest byte. +/// +/// \param[in] i_stringSize The size (in bytes) of \a i_string. +/// +/// \param[out] o_length The length of the decompressed string in \e bits. +/// +/// \param[in] i_data A pointer to the CompressedScanData header + data to be +/// decompressed. +/// +/// This API is required for integration with PHYP which does not support +/// malloc(). Applications in environments supporting malloc() can use +/// rs4_decompress() instead. +/// +/// \returns See \ref scan_compression_codes +int +_rs4_decompress(uint8_t* i_string, + uint32_t i_stringSize, + uint32_t* o_length, + const CompressedScanData* i_data); + + +/// Decompress a scan string compressed using the RS4 compression algorithm +/// +/// \param[out] 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[out] 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 \e bytes. +/// +/// \param[in] i_data A pointer to the CompressedScanData header + data to be +/// decompressed. +/// +/// \returns See \ref scan_compression_codes +int +rs4_decompress(uint8_t** o_string, + uint32_t* o_length, + const CompressedScanData* i_data); + + +/// Determine if an RS4 compressed scan string is all 0 +/// +/// \param[in] i_data A pointer to the CompressedScanData header + data to be +/// +/// \param[out] o_redundant Set to 1 if the RS4 string is the compressed form +/// of a scan string that is all 0; Otherwise set to 0. +/// +/// \returns See \ref scan _compression_code +int +rs4_redundant(const CompressedScanData* i_data, int* o_redundant); + + +#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. This error may also be returned by rs4_redundant() in the event +/// of inconsistencies in the compressed string. +CONST_UINT8_T(SCAN_DECOMPRESSION_SIZE_ERROR, 3); + +/// A buffer would overflow +/// +/// Either the caller-supplied memory buffer to _rs4_decompress() was too +/// small to contain the decompressed string, or a caller-supplied buffer to +/// _rs4_compress() was not large enough to hold the worst-case compressed +/// string. +CONST_UINT8_T(SCAN_COMPRESSION_BUFFER_OVERFLOW, 4); + +/// @} + +#endif // __P8_SCAN_COMPRESSION_H__ diff --git a/tools/image/ppeSetFixed.pl b/tools/image/ppeSetFixed.pl new file mode 100644 index 00000000..cd65761a --- /dev/null +++ b/tools/image/ppeSetFixed.pl @@ -0,0 +1,192 @@ +#!/usr/bin/perl +# Purpose: This perl script will parse the attribute and default list and +# and set the default values into the image. + +use strict; + +#------------------------------------------------------------------------------ +# Print Command Line Help +#------------------------------------------------------------------------------ +my $numArgs = $#ARGV + 1; +if ($numArgs < 3) +{ + print ("Usage: ppeSetFixed.pl ...\n"); + print (" This perl script will the attributes and default list to lookup the defaults\n"); + print (" and parse the attribute file to lookup the types.\n"); + print (" The default values will be set in the image.\n"); + print ("example:\n"); + print ("./ppeSetFixed.pl ./sbe_main.bin ../scripts/ppe_attributes.xml \\\n" ); + print ("../scripts/perv_attributes.xml ../scripts/proc_attributes.xml \\\n" ); + print ("../scripts/ex_attributes.xml ../scripts/eq_attributes.xml ../scripts/core_attributes.xml \n"); + exit(1); +} + +#------------------------------------------------------------------------------ +# Specify perl modules to use +#------------------------------------------------------------------------------ +use XML::Simple; +my $xml = new XML::Simple (KeyAttr=>[]); + + +my $xmlFiles = 0; +my $attCount = 0; +my $numIfAttrFiles = 0; +my @attrChipIds; +my @attrExIds; +my @attrCoreIds; +my @attrEqIds; +my @attrPervIds; + + + +#------------------------------------------------------------------------------ +# Element names +#------------------------------------------------------------------------------ +my $attribute = 'attribute'; + +#------------------------------------------------------------------------------ +# For each argument +#------------------------------------------------------------------------------ +my $image = $ARGV[0]; +my $argfile = $ARGV[1]; +my $entries = $xml->XMLin($argfile, ForceArray => ['entry']); + +if ( ! -e $image) {die "ppeSetFixed.pl: $image $!"}; + +foreach my $entr (@{$entries->{entry}}) { + + my $inname = $entr->{name}; + + # read XML file. The ForceArray option ensures that there is an array of + # elements even if there is only one such element in the file + + foreach my $argnum (2 .. $#ARGV) + { + my $infile = $ARGV[$argnum]; + + if ( ! -e $infile) {die "ppeSetFixed.pl: $infile $!"}; + + my $attributes = $xml->XMLin($infile, ForceArray => ['attribute']); + + #-------------------------------------------------------------------------- + # For each Attribute + #-------------------------------------------------------------------------- + foreach my $attr (@{$attributes->{attribute}}) + { + + if($attr->{id} eq $inname) { + + #------------------------------------------------------------------ + # Check that the AttributeId exists + #------------------------------------------------------------------ + if (! exists $attr->{id}) + { + print ("ppeSbeFixed.pl ERROR. Att 'id' missing\n"); + exit(1); + } + + + if($attr->{targetType} eq "TARGET_TYPE_PROC_CHIP") { + + push(@attrChipIds, $entr); + + } elsif($attr->{targetType} eq "TARGET_TYPE_CORE") { + + push(@attrCoreIds, $entr); + + } elsif($attr->{targetType} eq "TARGET_TYPE_EQ") { + + push(@attrEqIds, $entr); + + } elsif($attr->{targetType} eq "TARGET_TYPE_EX") { + + push(@attrExIds, $entr); + + } elsif($attr->{targetType} eq "TARGET_TYPE_PERV") { + + push(@attrPervIds, $entr); + + } else { + + print ("ppeSetFixed.pl ERROR. Wrong attribute type: $attr->{targetType}\n"); + exit(1); + + } + + } + } + } + +} + + + +setFixed("TARGET_TYPE_PROC_CHIP", @attrChipIds); +setFixed("TARGET_TYPE_CORE", @attrCoreIds); +setFixed("TARGET_TYPE_EQ", @attrEqIds); +setFixed("TARGET_TYPE_EX", @attrExIds); +setFixed("TARGET_TYPE_PERV", @attrPervIds); + + + +sub setFixed { + + my ($string, @entries) = @_; + + foreach my $attr (@entries) + { + + my $inname = $attr->{name}; + + my @values = $attr->{value}; + + + if(scalar @values > 0) { + + foreach my $val (@values) + { + + if(defined $val && ref($val) eq "") { + + if ($val =~ /(0x)?[0-9a-fA-F]+/) { + + my $systemRc = system("./sbe_default_tool $image $inname $val $string 0"); + + if ($systemRc) { + print "sbe_default_tool: error in execution\n"; + exit 1; + } + + } else { + print ("ppeSetFixed.pl ERROR. not hex\n"); + exit(1); + } + + } elsif(defined $val && ref($val) eq "ARRAY") { + + my $index = 0; + + foreach my $arr (@{$val}) { + + if(defined $arr && ref($arr) eq "") { + if ($arr =~ /(0x)?[0-9a-fA-F]+/) { + + my $systemRc = system("./sbe_default_tool $image $inname $arr $string $index"); + + if ($systemRc) { + print "sbe_default_tool: error in execution\n"; + exit 1; + } + + + } + } + $index++; + } + } + } + } + } +} + + diff --git a/tools/image/sbe_default_tool.c b/tools/image/sbe_default_tool.c new file mode 100644 index 00000000..2b1679ef --- /dev/null +++ b/tools/image/sbe_default_tool.c @@ -0,0 +1,286 @@ +/// \file sbe_default_tool.c +/// \brief SBE-XIP image setter tool for attributes in fixed section +/// +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define __PPE__ +#include "fapi2.H" +#include "proc_sbe_fixed.H" + +const char* g_usage = +"Usage: sbe_default_tool \n" +"The 'image' is the binary image with fixed section.\n" +"\n" +"The 'attribute' is the attribute to be set.\n" +"\n" +"The 'value' is the value of the attribute to be set.\n" +"\n" +"The 'target type' is the type of the target. The following targets are defined:\n" +"TARGET_TYPE_PROC_CHIP: chip target\n" +"TARGET_TYPE_PERV: pervasive target\n" +"TARGET_TYPE_CORE: core target\n" +"TARGET_TYPE_EQ: eq target\n" +"TARGET_TYPE_EX: ex target\n" +"\n" +"The 'index' is the index of the value. Checking is performed.\n" +"example:\n" +"./sbe_default_tool ./sbe_main.bin ATTR_PLL_RING 0x33CAFE34 TARGET_TYPE_PERV 0\n" +"./sbe_default_tool ./sbe_main.bin ATTR_SCRATCH_UINT8_1 12 TARGET_TYPE_PROC_CHIP 0\n" + ; + + +void assertTarget(const char* str, unsigned int index) +{ + + if(strcmp(str, "TARGET_TYPE_PROC_CHIP") == 0) { + if (index > 0) { + fprintf(stderr, "sbe_default_tool: index is larger than 0\n"); + exit(1); + } + return; + } else if(strcmp(str, "TARGET_TYPE_EX") == 0) { + if (index >= EX_TARGET_COUNT) { + fprintf(stderr, "sbe_default_tool: index is larger than EX_TARGET_COUNT\n"); + exit(1); + } + return; + } else if(strcmp(str, "TARGET_TYPE_EQ") == 0) { + if (index >= EQ_TARGET_COUNT) { + fprintf(stderr, "sbe_default_tool: index is larger than EQ_TARGET_COUNT\n"); + exit(1); + } + return; + } else if(strcmp(str, "TARGET_TYPE_CORE") == 0) { + if (index >= CORE_TARGET_COUNT) { + fprintf(stderr, "sbe_default_tool: index is larger than EQ_TARGET_COUNT\n"); + exit(1); + } + return; + } else if(strcmp(str, "TARGET_TYPE_PERV") == 0) { + if (index >= PERV_TARGET_COUNT) { + fprintf(stderr, "sbe_default_tool: index is larger than PERV_TARGET_COUNT\n"); + exit(1); + } + return; + } else { + + if (index >= PERV_TARGET_COUNT) { + fprintf(stderr, "sbe_default_tool: target not supported:"); + fprintf(stderr, " %s\n", str); + exit(1); + } + } +} + +void setAttribute(void* image, const char* attribute, unsigned int index, uint64_t val) { + + + SbeXipItem item; + void *thePointer; + int rc; + + rc = sbe_xip_find(image, attribute, &item); + if (rc) { + fprintf(stderr, "sbe_default_tool: attribute not existing:"); + fprintf(stderr, " %s", attribute); + exit(1); + } + + // debug purpose + //printf("offset in string section: 0x%x \n", be32toh(item.iv_toc->iv_id)); + //printf("address: 0x%x \n", item.iv_address); + + sbe_xip_image2host(image, item.iv_address, &thePointer); + + // debug purpose + //printf("pointer1: 0x%x \n", thePointer); + //printf("val: 0x%llx \n", val); + + if(item.iv_toc->iv_type == SBE_XIP_UINT8) { + + *((uint8_t*)thePointer + index) = (uint8_t)val; + + } else if(item.iv_toc->iv_type == SBE_XIP_INT8) { + + *((int8_t*)thePointer + index) = (int8_t)val; + + } else if(item.iv_toc->iv_type == SBE_XIP_UINT16) { + + *((uint16_t*)thePointer + index) = (uint16_t)val; + + } else if(item.iv_toc->iv_type == SBE_XIP_INT16) { + + *((int16_t*)thePointer + index) = (int16_t)val; + + } else if(item.iv_toc->iv_type == SBE_XIP_UINT32) { + + *((uint32_t*)thePointer + index) = (uint32_t)val; + + } else if(item.iv_toc->iv_type == SBE_XIP_INT32) { + + *((int32_t*)thePointer + index) = (int32_t)val; + + } else if(item.iv_toc->iv_type == SBE_XIP_UINT64) { + + *((uint64_t*)thePointer + index) = (uint64_t)val; + + } else if(item.iv_toc->iv_type == SBE_XIP_INT64) { + + *((int64_t*)thePointer + index) = (int64_t)val; + + } else { + fprintf(stderr, "sbe_default_tool: type not available"); + exit(1); + } + + + + + SBE_XIP_SECTION_NAMES(section_name); + SBE_XIP_TYPE_STRINGS(type_name); + + // debug purpose + //printf("pointer2: 0x%x \n", thePointer); + //printf("section id: %s \n", section_name[item.iv_toc->iv_section]); + //printf("location in section: 0x%x \n", be32toh(item.iv_toc->iv_data)); + //printf("type name: %s \n", type_name[item.iv_toc->iv_type]); + + return; +} + + +uint64_t getAttribute(void* image, const char* attribute, unsigned int index) { + + uint64_t val = 0; + + SbeXipItem item; + void *thePointer; + int rc; + + rc = sbe_xip_find(image, attribute, &item); + if (rc) { + fprintf(stderr, "sbe_default_tool: attribute not existing:"); + fprintf(stderr, " %s", attribute); + exit(1); + } + + sbe_xip_image2host(image, item.iv_address, &thePointer); + + if(item.iv_toc->iv_type == SBE_XIP_UINT8) { + + val = *((uint8_t*)thePointer + index); + + } else if(item.iv_toc->iv_type == SBE_XIP_INT8) { + + val = *((int8_t*)thePointer + index); + val &= 0xFF; + + } else if(item.iv_toc->iv_type == SBE_XIP_UINT16) { + + val = *((uint16_t*)thePointer + index); + + } else if(item.iv_toc->iv_type == SBE_XIP_INT16) { + + val = *((int16_t*)thePointer + index); + val &= 0xFFFF; + + } else if(item.iv_toc->iv_type == SBE_XIP_UINT32) { + + val = *((uint32_t*)thePointer + index); + + } else if(item.iv_toc->iv_type == SBE_XIP_INT32) { + + val = *((int32_t*)thePointer + index); + val &= 0xFFFFFFFF; + + } else if(item.iv_toc->iv_type == SBE_XIP_UINT64) { + + val = *((uint64_t*)thePointer + index); + + } else if(item.iv_toc->iv_type == SBE_XIP_INT64) { + + val = *((int64_t*)thePointer + index); + + } else { + fprintf(stderr, "sbe_default_tool: type not available"); + exit(1); + } + + + + return val; +} + +int main(int argc, const char** argv) +{ + + int fileFd, rc; + void* image; + struct stat buf; + + if(argc != 6) { + fprintf(stderr, "sbe_default_tool: argument missing\n"); + fprintf(stderr, g_usage); + exit(1); + } + + printf("sbe_default_tool %s %s %s %s %s\n", argv[1], argv[2], argv[3], argv[4], argv[5]); + + fileFd = open(argv[1], O_RDWR); + if (fileFd < 0) { + fprintf(stderr, "sbe_default_tool: open() of the file to be appended failed"); + exit(1); + } + + rc = fstat(fileFd, &buf); + if (rc) { + fprintf(stderr, "sbe_default_tool: fstat() of the file to be appended failed"); + exit(1); + } + + image = mmap(0, buf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fileFd, 0); + if (image == MAP_FAILED) { + fprintf(stderr, "sbe_default_tool: mmap() of the file to be appended failed"); + exit(1); + } + + + uint64_t val=strtoull(argv[3], 0, 0); + + unsigned int index = strtoul(argv[5], 0, 10); + + assertTarget(argv[4], index); + + setAttribute(image, argv[2], index, val); + + uint64_t check = getAttribute(image, argv[2], index); + + if((check & val) != check) { + + fprintf(stderr, "sbe_default_tool: set and get values not equal"); + fprintf(stderr, "%lx != %lx\n", check, val); + exit(1); + + } + + rc = close(fileFd); + if (rc) { + fprintf(stderr, "sbe_default_tool: close() of modified image failed"); + exit(1); + } + + + return 0; +} diff --git a/tools/image/sbe_xip_tool.c b/tools/image/sbe_xip_tool.c new file mode 100644 index 00000000..ae136858 --- /dev/null +++ b/tools/image/sbe_xip_tool.c @@ -0,0 +1,2014 @@ +// $Id: sbe_xip_tool.c,v 1.13 2014/06/27 20:50:16 maploetz Exp $ + +/// \file sbe_xip_tool.c +/// \brief SBE-XIP image search/edit tool +/// +/// Note: This file was originally stored under .../procedures/ipl/sbe. It +/// was moved here at version 1.19. + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + + +#define __PPE__ +#include "fapi2.H" +#include "proc_sbe_fixed.H" +#include "sbe_xip_image.h" + +#include "sbe_link.H" +#include "p9_image_help_base.H" +#include "p9_ring_identification.H" +#include "p9_scan_compression.H" + +// Usage: sbe_xip_tool [- ...] normalize +// sbe_xip_tool [- ...] get +// sbe_xip_tool [- ...] getv +// sbe_xip_tool [- ...] set [ ... ] +// sbe_xip_tool [- ...] setv [ ... ] +// sbe_xip_tool [- ...] report [] +// sbe_xip_tool [- ...] append
+// sbe_xip_tool [- ...] delete [ ... ] +// sbe_xip_tool [- ...] dis
\n"// +// +// This simple application uses the SBE-XIP image APIs to normalize, search +// update and edit SBE-XIP images. This program encapsulates several commands +// in a common command framework which requires an image to operate on, a +// command name, and command arguments that vary by command. Commands that +// modify the image always rewrite the image in-place in the filesystem; +// however the original image is only modified if the command has completed +// without error. +// +// The program operates on an SBE-XIP format binary image, which must be +// normalized - unless the tool is being called to normalize the image in the +// first place using the 'normalize' command. The tool also validates the +// image prior to operating on the image. +// +// The 'get' command retrieves a scalar value from the image and prints its +// representation on stdout (followed by a newline). Scalar integer values +// and image addresses are printed as hex numbers (0x...). Strings are printed +// verbatim. +// +// The 'getv' command retrieves a vector element from the image and prints its +// representation on stdout (followed by a newline). Integer values +// and image addresses are printed as hex numbers (0x...). Vectors of strings +// are not supported. +// +// The 'set' command allows setting integer and string values in the image. +// New integer values can be specified in decimal or hex (0x...). Strings are +// taken verbatim from the command line. Note that new string values will be +// silently truncated to the length of the current string if the new value is +// longer than the current string. Updating address values is currently not +// supported. Any number of item/value pairs can be specified with a single +// 'set' command. +// +// The 'setv' command is provided to set individual vector elements of +// integral arrays. +// +// The 'report' command prints a report including a dump of the header and +// section table, a listing of the types and values of all items that appear +// in the TOC, and a dump of the .halt section. The TOC listing includes the +// sequence number of the entry in the TOC, the item name, the item type and +// the item value. The .halt listing displays a map of HALT PC values to the +// string form of the halt code associated with the HALT address. The optional +// expression, if present, is a POSIX Basic Regular Expression. If +// is specified, then no header, section table or .halt dumps are +// provided, and only the TOC entries matching will be listed. +// +// The 'append' command either creates or extends the section named by the +// section argument, by appending the contents of the named file verbatim. +// Currently the section must either be the final (highest address) section of +// the image, or must be empty, in which case the append command creates the +// section as the final section of the image. The 'append' command writes the +// relocatable image address where the input file was loaded to stdout. +// +// The 'delete' command deletes 0 or more sections, starting with . +// Each section to be deleted must either be the final (highest address) +// section of the image at the time it is deleted, or must be empty. The +// 'delete' command writes the size of the final modified image to stdout. +// +// The 'dis' command disassembles the section named by the section argument. +// Note that the section name .rings_summary, which is not an actual XIP +// section name, merely indicates to summarize the .rings section. +// +// The following -i are supported: +// -ifs +// causes the validation step to ignore image size check against the file +// size. +// -iv +// causes all validation checking to be ignored. (Skips validation step.) + +const char* g_usage = +"Usage: sbe_xip_tool [-i ...] normalize\n" +" sbe_xip_tool [-i ...] get \n" +" sbe_xip_tool [-i ...] getv \n" +" sbe_xip_tool [-i ...] set [ ... ]\n" +" sbe_xip_tool [-i ...] setv [ ... ]\n" +" sbe_xip_tool [-i ...] report []\n" +" sbe_xip_tool [-i ...] append
\n" +" sbe_xip_tool [-i ...] delete [ ... ]\n" +" sbe_xip_tool [-i ...] dis
\n"//\n" +"\n" +"This simple application uses the SBE-XIP image APIs to normalize, search\n" +"update and edit SBE-XIP images. This program encapsulates several commands\n" +"in a common command framework which requires an image to operate on, a\n" +"command name, and command arguments that vary by command. Commands that\n" +"modify the image always rewrite the image in-place in the filesystem;\n" +"however the original image is only modified if the command has completed\n" +"without error.\n" +"\n" +"The program operates on an SBE-XIP format binary image, which must be\n" +"normalized - unless the tool is being called to normalize the image in the\n" +"first place using the 'normalize' command. The tool also validates the\n" +"image prior to operating on the image.\n" +"\n" +"The 'get' command retrieves a scalar value from the image and prints its\n" +"representation on stdout (followed by a newline). Scalar integer values\n" +"and image addresses are printed as hex numbers (0x...). Strings are printed\n" +"verbatim.\n" +"\n" +"The 'getv' command retrieves a vector element from the image and prints its\n" +"representation on stdout (followed by a newline). Integer values\n" +"and image addresses are printed as hex numbers (0x...). Vectors of strings\n" +"are not supported.\n" +"\n" +"The 'set' command allows setting integer and string values in the image.\n" +"New integer values can be specified in decimal or hex (0x...). Strings are\n" +"taken verbatim from the command line. Note that new string values will be\n" +"silently truncated to the length of the current string if the new value is\n" +"longer than the current string. Updating address values is currently not\n" +"supported. Any number of item/value pairs can be specified with a single\n" +"'set' command.\n" +"\n" +"The 'setv' command is provided to set individual vector elements of\n" +"integral arrays.\n" +"\n" +"The 'report' command prints a report including a dump of the header and\n" +"section table, a listing of the types and values of all items that appear\n" +"in the TOC, and a dump of the .halt section. The TOC listing includes the\n" +"sequence number of the entry in the TOC, the item name, the item type and\n" +"the item value. The .halt listing displays a map of HALT PC values to the\n" +"string form of the halt code associated with the HALT address. The optional\n" +" expression, if present, is a POSIX Basic Regular Expression. If\n" +" is specified, then no header, section table or .halt dumps are\n" +"provided, and only the TOC entries matching will be listed.\n" +"\n" +"The 'append' command either creates or extends the section named by the\n" +"section argument, by appending the contents of the named file verbatim.\n" +"Currently the section must either be the final (highest address) section of\n" +"the image, or must be empty, in which case the append command creates the\n" +"section as the final section of the image. The 'append' command writes the\n" +"relocatable image address where the input file was loaded to stdout.\n" +"\n" +"The 'delete' command deletes 0 or more sections, starting with .\n" +"Each section to be deleted must either be the final (highest address)\n" +"section of the image at the time it is deleted, or must be empty. The\n" +"'delete' command writes the size of the final modified image to stdout.\n" +"\n" +"The 'dis' command disassembles the section named by the section argument.\n" +"Note that the section name .rings_summary, which is not an actual XIP\n" +"section name, merely indicates to summarize the .rings section.\n" +"\n" +"-i:\n" +"\t-ifs Causes the validation step to ignore image size check against the\n" +"\tfile size.\n" +"\t-iv Causes all validation checking to be ignored.\n" + ; + +SBE_XIP_ERROR_STRINGS(g_errorStrings); +SBE_XIP_TYPE_STRINGS(g_typeStrings); +SBE_XIP_TYPE_ABBREVS(g_typeAbbrevs); +SBE_XIP_SECTION_NAMES(g_sectionNames); +// Disassembler error support. +DIS_ERROR_STRINGS(g_errorStringsDis); + +#define ERRBUF_SIZE 60 + +typedef struct { + int index; + int regex; + regex_t preg; +} ReportControl; + +off_t g_imageSize; + + +// 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; +} + +// Normalize an SBE-XIP image. We normalize a copy of the image first so that +// the original image will be available for debugging in case the +// normalization fails, then validate and copy the normalized image back to +// the mmap()-ed file. + +int +normalize(void* io_image, const int i_argc, const char** i_argv, uint32_t i_maskIgnores) +{ + int rc; + void *copy; + + do { + + // The 'normalize' command takes no arguments + + if (i_argc != 0) { + fprintf(stderr, g_usage); + exit(1); + } + + copy = malloc(g_imageSize); + if (copy == 0) { + perror("malloc() failed : "); + exit(1); + } + + memcpy(copy, io_image, g_imageSize); + + rc = sbe_xip_normalize(copy); + if (rc) break; + + if ( !(i_maskIgnores & SBE_XIP_IGNORE_ALL) ) { + rc = sbe_xip_validate2(copy, g_imageSize, i_maskIgnores); + } + if (rc) break; + + memcpy(io_image, copy, g_imageSize); + + } while (0); + + return rc; +} + + +// Print a line of a report, listing the index, symbol, type and current +// value. + +int +tocListing(void* io_image, + const SbeXipItem* i_item, + void* arg) +{ + int rc; + ReportControl *control; + uint64_t data; + char* s; + + control = (ReportControl*)arg; + + do { + rc = 0; + + if (control->regex) { + if (regexec(&(control->preg), i_item->iv_id, 0, 0, 0)) { + break; + } + } + + printf("0x%04x | %-42s | %s | ", + control->index, i_item->iv_id, + SBE_XIP_TYPE_STRING(g_typeAbbrevs, i_item->iv_type)); + + switch (i_item->iv_type) { + case SBE_XIP_UINT8: + rc = sbe_xip_get_scalar(io_image, i_item->iv_id, &data); + if (rc) break; + printf("0x%02x", (uint8_t)data); + break; + case SBE_XIP_UINT32: + rc = sbe_xip_get_scalar(io_image, i_item->iv_id, &data); + if (rc) break; + printf("0x%08x", (uint32_t)data); + break; + case SBE_XIP_UINT64: + rc = sbe_xip_get_scalar(io_image, i_item->iv_id, &data); + if (rc) break; + printf("0x%016llx", data); + break; + case SBE_XIP_STRING: + rc = sbe_xip_get_string(io_image, i_item->iv_id, &s); + if (rc) break; + printf("%s", s); + break; + case SBE_XIP_ADDRESS: + rc = sbe_xip_get_scalar(io_image, i_item->iv_id, &data); + if (rc) break; + printf("0x%04x:0x%08x", + (uint16_t)((data >> 32) & 0xffff), + (uint32_t)(data & 0xffffffff)); + break; + default: + rc = SBE_XIP_BUG; + break; + } + printf("\n"); + } while (0); + control->index += 1; + return rc; +} + + +// Dump the image header, including the section table + +int +dumpHeader(void* i_image) +{ + int i; + SbeXipHeader header; + SbeXipSection* section; + char magicString[9]; + + SBE_XIP_SECTION_NAMES(section_name); + + // Dump header information. Since the TOC may not exist we need to get + // the information from the header explicitly. + + sbe_xip_translate_header(&header, (SbeXipHeader*)i_image); + + memcpy(magicString, (char*)(&(((SbeXipHeader*)i_image)->iv_magic)), 8); + magicString[8] = 0; + + printf("Magic Number : 0x%016llx \"%s\"\n", + header.iv_magic, magicString); + printf("Header Version : 0x%02x\n", header.iv_headerVersion); + printf("Link Address : 0x%016llx\n", header.iv_linkAddress); + printf("Entry Offset : 0x%08x\n", (uint32_t)header.iv_entryOffset); + printf("Image Size : 0x%08x (%d)\n", + header.iv_imageSize, header.iv_imageSize); + printf("Normalized : %s\n", header.iv_normalized ? "Yes" : "No"); + printf("TOC Sorted : %s\n", header.iv_tocSorted ? "Yes" : "No"); + printf("Build Date : %02d/%02d/%04d\n", + (header.iv_buildDate / 100) % 100, + header.iv_buildDate % 100, + header.iv_buildDate / 10000); + printf("Build Time : %02d:%02d\n", + header.iv_buildTime / 100, + header.iv_buildTime % 100); + printf("Build User : %s\n", header.iv_buildUser); + printf("Build Host : %s\n", header.iv_buildHost); + printf("\n"); + + printf("Section Table : Offset Size\n"); + printf("\n"); + + for (i = 0; i < SBE_XIP_SECTIONS; i++) { + section = &(header.iv_section[i]); + printf("%-16s 0x%08x 0x%08x (%d)\n", + section_name[i], + section->iv_offset, section->iv_size, section->iv_size); + } + + printf("\n"); + + return 0; +} + + +// Dump an entry from .halt + +int +haltListing(void* io_image, + const uint64_t i_homerAddress, + const char* i_rcString, + void* io_arg) +{ + printf("%016llx : %s\n", i_homerAddress, i_rcString); + return 0; +} + + +// Print a report + +int +report(void* io_image, const int i_argc, const char** i_argv) +{ + int rc; + ReportControl control; + char errbuf[ERRBUF_SIZE]; + + do { + + // Basic syntax check : [] + + if (i_argc > 1) { + fprintf(stderr, g_usage); + exit(1); + } + + // Compile a regular expression if supplied + + if (i_argc == 1) { + rc = regcomp(&(control.preg), i_argv[0], REG_NOSUB); + if (rc) { + regerror(rc, &(control.preg), errbuf, ERRBUF_SIZE); + fprintf(stderr, "Error from regcomp() : %s\n", errbuf); + exit(1); + } + control.regex = 1; + } else { + control.regex = 0; + dumpHeader(io_image); + printf("TOC Report\n\n"); + } + + // Map the TOC with the mapReport() function + + control.index = 0; + rc = sbe_xip_map_toc(io_image, tocListing, (void*)(&control)); + if (rc) break; + + // Dump the .halt section + + if (i_argc == 0) { + printf("\nHALT report\n\n"); + rc = sbe_xip_map_halt(io_image, haltListing, 0); + if (rc == SBE_XIP_ITEM_NOT_FOUND) { + rc = 0; + } + if (rc) break; + } + + } while (0); + + return rc; +} + + +// Set a scalar or vector element values in the image. The 'i_setv' argument +// indicates set/setv (0/1). + +int +set(void* io_image, const int i_argc, const char** i_argv, int i_setv) +{ + int rc, arg, base, clause_args, index_val; + SbeXipItem item; + unsigned long long newValue; + const char *key, *index, *value; + char *endptr; + + do { + + // Basic syntax check: [ ... ] + // Basic syntax check: [ ... ] + + clause_args = (i_setv ? 3 : 2); + + if ((i_argc % clause_args) != 0) { + fprintf(stderr, g_usage); + exit(1); + } + + for (arg = 0; arg < i_argc; arg += clause_args) { + + key = i_argv[arg]; + if (i_setv) { + index = i_argv[arg + 1]; + index_val = strtol(index, 0, 0); + value = i_argv[arg + 2]; + } else { + index = ""; + index_val = 0; + value = i_argv[arg + 1]; + } + + // Search for the item to see what type of data it expects, then + // case split on the type. + + rc = sbe_xip_find(io_image, key, &item); + if (rc) break; + + if (index_val < 0) { + fprintf(stderr, + "Illegal negative vector index %s for %s\n", + index, key); + exit(1); + } else if ((item.iv_elements != 0) && + (index_val >= item.iv_elements)) { + fprintf(stderr, + "Index %s out-of-bounds for %s (%d elements)\n", + index, key, item.iv_elements); + exit(1); + } + + switch (item.iv_type) { + case SBE_XIP_UINT8: + case SBE_XIP_UINT32: + case SBE_XIP_UINT64: + + // We need to do a bit of preprocessing on the string to + // determine its format and set the base for strtoull(), + // otherwise strtoull() will be confused by leading zeros + // e.g. in time strings generated by `date +%H%M`, and try to + // process the string as octal. + + if ((strlen(value) >= 2) && (value[0] == '0') && + ((value[1] == 'x') || (value[1] == 'X'))) { + base = 16; + } else { + base = 10; + } + + errno = 0; + newValue = strtoull(value, &endptr, base); + if ((errno != 0) || (endptr != (value + strlen(value)))) { + fprintf(stderr, + "Error parsing putative integer value : %s\n", + value); + exit(1); + } + + switch (item.iv_type) { + + case SBE_XIP_UINT8: + if ((uint8_t)newValue != newValue) { + fprintf(stderr, + "Value 0x%016llx too large for 8-bit type\n", + newValue); + exit(1); + } + break; + + case SBE_XIP_UINT32: + if ((uint32_t)newValue != newValue) { + fprintf(stderr, + "Value 0x%016llx too large for 32-bit type\n", + newValue); + exit(1); + } + break; + + case SBE_XIP_UINT64: + break; + + default: + break; + } + + rc = sbe_xip_set_element(io_image, key, index_val, newValue); + if (rc) rc = SBE_XIP_BUG; + break; + + case SBE_XIP_STRING: + + if (i_setv) { + fprintf(stderr, "Can't use 'setv' for string data %s\n", + key); + exit(1); + } + rc = sbe_xip_set_string(io_image, key, (char*)value); + if (rc) rc = SBE_XIP_BUG; + break; + + default: + fprintf(stderr, + "Item %s has type %s, " + "which is not supported for '%s'.\n", + i_argv[arg], + SBE_XIP_TYPE_STRING(g_typeStrings, item.iv_type), + (i_setv ? "setv" : "set")); + exit(1); + break; + } + + if (rc) break; + + } + } while (0); + + //if good rc, we need to msync the mmaped file to push contents to + //the actual file. Per man page this is required although some + //file systems (notably AFS) don't seem to require (GSA does) + if(!rc) + { + uint8_t i = 0; + do { + rc = msync(io_image, g_imageSize , MS_SYNC); + if(rc) + { + i++; + fprintf(stderr, + "msync failed with errno %d\n", errno); + } + } while(rc && i < 5); + + if(rc) + { + exit(3); + } + } + + return rc; +} + + +// Get a value from the image, and return on stdout. The 'i_getv' argument +// indicates get/getv (0/1) + +int +get(void* i_image, const int i_argc, const char** i_argv, int i_getv) +{ + int rc, nargs, index_val; + SbeXipItem item; + const char *key, *index; + uint64_t data; + char* s; + + do { + + // Basic syntax check: + // Basic syntax check: + + nargs = (i_getv ? 2 : 1); + + if (i_argc != nargs) { + fprintf(stderr, g_usage); + exit(1); + } + + key = i_argv[0]; + if (i_getv) { + index = i_argv[1]; + index_val = strtol(index, 0, 0); + } else { + index = ""; + index_val = 0; + } + + // Search for the item to determine its type, then case split on the + // type. + + rc = sbe_xip_find(i_image, key, &item); + if (rc) break; + + if (index_val < 0) { + fprintf(stderr, + "Illegal negative vector index %s for %s\n", + index, key); + exit(1); + } else if ((item.iv_elements != 0) && + (index_val >= item.iv_elements)) { + fprintf(stderr, "Index %s out-of-bounds for %s (%d elements)\n", + index, key, item.iv_elements); + exit(1); + } + + switch (item.iv_type) { + + case SBE_XIP_UINT8: + case SBE_XIP_UINT32: + case SBE_XIP_UINT64: + rc = sbe_xip_get_element(i_image, key, index_val, &data); + if (rc) { + rc = SBE_XIP_BUG; + break; + } + switch (item.iv_type) { + case SBE_XIP_UINT8: + printf("0x%02x\n", (uint8_t)data); + break; + case SBE_XIP_UINT32: + printf("0x%08x\n", (uint32_t)data); + break; + case SBE_XIP_UINT64: + printf("0x%016llx\n", data); + break; + default: + break; + } + break; + + case SBE_XIP_ADDRESS: + if (i_getv) { + fprintf(stderr, "Can't use 'getv' for address data : %s\n", + key); + exit(1); + } + rc = sbe_xip_get_scalar(i_image, key, &data); + if (rc) { + rc = SBE_XIP_BUG; + break; + } + printf("0x%012llx\n", data); + break; + + case SBE_XIP_STRING: + if (i_getv) { + fprintf(stderr, "Can't use 'getv' for string data : %s\n", + key); + exit(1); + } + rc = sbe_xip_get_string(i_image, key, &s); + if (rc) { + rc = SBE_XIP_BUG; + break; + } + printf("%s\n", s); + break; + + default: + fprintf(stderr, "%s%d : Bug, unexpected type %d\n", + __FILE__, __LINE__, item.iv_type); + exit(1); + break; + } + } while (0); + + return rc; +} + + +// strtoul() with application-specific error handling + +unsigned long +localStrtoul(const char* s) +{ + unsigned long v; + char* endptr; + + errno = 0; + v = strtoul(s, &endptr, 0); + if ((errno != 0) || (endptr != (s + strlen(s)))) { + fprintf(stderr, + "Error parsing putative integer value : %s\n", + s); + exit(1); + } + return v; +} + + +// Append a file to section + +int +append(const char* i_imageFile, const int i_imageFd, void* io_image, + int i_argc, const char** i_argv) +{ + int fileFd, newImageFd, sectionId, rc; + struct stat buf; + const char* section; + const char* file; + void* appendImage; + void* newImage; + uint32_t size, newSize, sectionOffset; + uint64_t homerAddress; + + do { + + // Basic syntax check:
+ + if (i_argc != 2) { + fprintf(stderr, g_usage); + exit(1); + } + section = i_argv[0]; + file = i_argv[1]; + + + // Translate the section name to a section Id + + for (sectionId = 0; sectionId < SBE_XIP_SECTIONS; sectionId++) { + if (strcmp(section, g_sectionNames[sectionId]) == 0) { + break; + } + } + if (sectionId == SBE_XIP_SECTIONS) { + fprintf(stderr, "Unrecognized section name : '%s;\n", + section); + exit(1); + } + + + // Open and mmap the file to be appended + + fileFd = open(file, O_RDONLY); + if (fileFd < 0) { + perror("open() of the file to be appended failed : "); + exit(1); + } + + rc = fstat(fileFd, &buf); + if (rc) { + perror("fstat() of the file to be appended failed : "); + exit(1); + } + + appendImage = mmap(0, buf.st_size, PROT_READ, MAP_SHARED, fileFd, 0); + if (appendImage == MAP_FAILED) { + perror("mmap() of the file to be appended failed : "); + exit(1); + } + + + // malloc() a buffer for the new image, adding space for alignment + + rc = sbe_xip_image_size(io_image, &size); + if (rc) break; + + newSize = size + buf.st_size + SBE_XIP_MAX_SECTION_ALIGNMENT; + + newImage = malloc(newSize); + + if (newImage == 0) { + fprintf(stderr, "Can't malloc() a buffer for the new image\n"); + exit(1); + } + + + // Copy the image. At this point the original image file must be + // closed. + + memcpy(newImage, io_image, size); + + rc = close(i_imageFd); + if (rc) { + perror("close() of the original image file failed : "); + exit(1); + } + + + // Do the append and print the image address where the data was loaded. + // We will not fail for unaligned addresses, as we have no knowledge + // of whether or why the user wants the final image address. + + rc = sbe_xip_append(newImage, sectionId, + appendImage, buf.st_size, + newSize, §ionOffset); + if (rc) break; + + rc = sbe_xip_section2image(newImage, sectionId, sectionOffset, + &homerAddress); + if (rc && (rc != SBE_XIP_ALIGNMENT_ERROR)) break; + + printf("0x%016llx\n", homerAddress); + + + // Now write the new image back to the filesystem + + newImageFd = open(i_imageFile, O_WRONLY | O_TRUNC); + if (newImageFd < 0) { + perror("re-open() of image file failed : "); + exit(1); + } + + rc = sbe_xip_image_size(newImage, &size); + if (rc) break; + + rc = write(newImageFd, newImage, size); + if ((rc < 0) || ((uint32_t)rc != size)) { + perror("write() of modified image failed : "); + exit(1); + } + + rc = close(newImageFd); + if (rc) { + perror("close() of modified image failed : "); + exit(1); + } + } while (0); + + return rc; +} + + +// Delete 0 or more sections in order. + +int +deleteSection(const char* i_imageFile, const int i_imageFd, void* io_image, + int i_argc, const char** i_argv) +{ + int newImageFd, sectionId, rc, argc; + const char* section; + const char** argv; + void* newImage; + uint32_t size; + + do { + + // malloc() a buffer for the new image + + rc = sbe_xip_image_size(io_image, &size); + if (rc) break; + + newImage = malloc(size); + + if (newImage == 0) { + fprintf(stderr, "Can't malloc() a buffer for the new image\n"); + exit(1); + } + + + // Copy the image. At this point the original image file must be + // closed. + + memcpy(newImage, io_image, size); + + rc = close(i_imageFd); + if (rc) { + perror("close() of the original image file failed : "); + exit(1); + } + + // Delete the sections in argument order + + for (argc = i_argc, argv = i_argv; argc != 0; argc--, argv++) { + + // Translate the section name to a section Id + + section = *argv; + + for (sectionId = 0; sectionId < SBE_XIP_SECTIONS; sectionId++) { + if (strcmp(section, g_sectionNames[sectionId]) == 0) { + break; + } + } + if (sectionId == SBE_XIP_SECTIONS) { + fprintf(stderr, "Unrecognized section name : '%s;\n", + section); + exit(1); + } + + // Delete the section + + rc = sbe_xip_delete_section(newImage, sectionId); + if (rc) break; + } + if (rc) break; + + // Print the final size of the new image + + rc = sbe_xip_image_size(newImage, &size); + if (rc) break; + + printf("%u\n", size); + + // Now write the new image back to the filesystem + + newImageFd = open(i_imageFile, O_WRONLY | O_TRUNC); + if (newImageFd < 0) { + perror("re-open() of image file failed : "); + exit(1); + } + + rc = write(newImageFd, newImage, size); + if ((rc < 0) || ((uint32_t)rc != size)) { + perror("write() of modified image failed : "); + exit(1); + } + + rc = close(newImageFd); + if (rc) { + perror("close() of modified image failed : "); + exit(1); + } + } while (0); + + return rc; +} + + +// 'TEST' is an undocumented command provided to test the APIs. It searches +// and modifies a copy of the image but puts the image back together as it +// was, then verifies that the the original image and the copy are identical. + +#define BOMB_IF(test) \ + if (test) { \ + fprintf(stderr, "%s:%d : Error in TEST\n", \ + __FILE__, __LINE__); \ + exit(1); \ + } + +#define BOMB_IF_RC \ + if (rc) { \ + fprintf(stderr, "%s:%d : Error in TEST, rc = %s\n", \ + __FILE__, __LINE__, \ + SBE_XIP_ERROR_STRING(g_errorStrings, rc)); \ + exit(1); \ + } + + +int +TEST(void* io_image, const int i_argc, const char** i_argv) +{ + int rc; + uint64_t linkAddress, entryPoint, data, data1, magicKey, entry_offset[2]; + char *key, *revision, *revdup, *longString, *shortString; + void *originalImage, *deleteAppendImage; + uint32_t imageSize; + SbeXipItem item; + SbeXipHeader header; + SbeXipSection section; + //ProcSbeFixed* fixed; + uint32_t tocSize; + + do { + rc = sbe_xip_image_size(io_image, &imageSize); + BOMB_IF_RC; + originalImage = malloc(imageSize); + BOMB_IF(originalImage == 0); + memcpy(originalImage, io_image, imageSize); + + rc = sbe_xip_get_scalar(io_image, "toc_sorted", &data); + BOMB_IF_RC; + BOMB_IF(data != 1); + + rc = sbe_xip_get_scalar(io_image, "image_size", &data); + BOMB_IF_RC; + BOMB_IF(data != (uint64_t)g_imageSize); + + rc = sbe_xip_get_scalar(io_image, "magic", &magicKey); + BOMB_IF_RC; + + switch (magicKey) { + case SBE_BASE_MAGIC: + key = (char*)"proc_sbe_fabricinit_revision"; + rc = sbe_xip_get_string(io_image, key, &revision); + BOMB_IF_RC; + BOMB_IF(strncmp(revision, "1.", 2) != 0); + break; + case SBE_SEEPROM_MAGIC: + key = (char*)""; + // Can't do this test here as the TOC has been stripped + break; + case SBE_CENTAUR_MAGIC: + key = (char*)"cen_sbe_initf_revision"; + rc = sbe_xip_get_string(io_image, key, &revision); + BOMB_IF_RC; + BOMB_IF(strncmp(revision, "1.", 2) != 0); + break; + default: + BOMB_IF(1); + break; + } + + rc = sbe_xip_get_scalar(io_image, "link_address", &linkAddress); + BOMB_IF_RC; + if (magicKey != SBE_SEEPROM_MAGIC) { + rc = sbe_xip_get_scalar(io_image, "entry_point", &entryPoint); + BOMB_IF_RC; + } + rc = sbe_xip_get_scalar(io_image, "entry_offset", &data); + BOMB_IF_RC; + BOMB_IF((magicKey != SBE_SEEPROM_MAGIC) && (entryPoint != (linkAddress + data))); + + rc = + sbe_xip_set_scalar(io_image, "toc_sorted", 0) || + sbe_xip_set_scalar(io_image, "image_size", 0); + BOMB_IF_RC; + + data = 0; + data += (rc = sbe_xip_get_scalar(io_image, "toc_sorted", &data), data); + BOMB_IF_RC; + data += (rc = sbe_xip_get_scalar(io_image, "image_size", &data), data); + BOMB_IF_RC; + BOMB_IF(data != 0); + + // Write back keys found during read check. + + rc = + sbe_xip_set_scalar(io_image, "toc_sorted", 1) || + sbe_xip_set_scalar(io_image, "image_size", g_imageSize); + BOMB_IF_RC; + + // We'll rewrite the revision keyword with a long string and a short + // string, and verify that rewriting is being done correctly. In the + // end we copy the original revision string back in, which is safe + // because the memory allocation for strings does not change when they + // are modified. + + revdup = strdup(revision); + longString = (char*)"A very long string"; + shortString = (char*)"?"; + + if (magicKey != SBE_SEEPROM_MAGIC) { + rc = + sbe_xip_set_string(io_image, key, longString) || + sbe_xip_get_string(io_image, key, &revision); + BOMB_IF_RC; + BOMB_IF((strlen(revision) != strlen(revdup)) || + (strncmp(revision, longString, strlen(revdup)) != 0)); + + rc = + sbe_xip_set_string(io_image, key, shortString) || + sbe_xip_get_string(io_image, key, &revision); + BOMB_IF_RC; + BOMB_IF(strcmp(revision, shortString) != 0); + + memcpy(revision, revdup, strlen(revdup) + 1); + } + + // Use sbe_xip_[read,write]_uint64 to modify the image and restore it + // to its original form. + + rc = sbe_xip_find(io_image, "entry_offset", &item); + BOMB_IF_RC; + rc = sbe_xip_get_scalar(io_image, "entry_offset", &(entry_offset[0])); + BOMB_IF_RC; + + rc = sbe_xip_read_uint64(io_image, item.iv_address, &(entry_offset[1])); + BOMB_IF_RC; + BOMB_IF(entry_offset[0] != entry_offset[1]); + + rc = sbe_xip_write_uint64(io_image, item.iv_address, + 0xdeadbeefdeadc0deull); + BOMB_IF_RC; + rc = sbe_xip_read_uint64(io_image, item.iv_address, &(entry_offset[1])); + BOMB_IF_RC; + BOMB_IF(entry_offset[1] != 0xdeadbeefdeadc0deull); + + rc = sbe_xip_write_uint64(io_image, item.iv_address, entry_offset[0]); + BOMB_IF_RC; + + // Try sbe_xip_get_section against the translated header + + sbe_xip_translate_header(&header, (SbeXipHeader*)io_image); + rc = sbe_xip_get_section(io_image, SBE_XIP_SECTION_TOC, §ion); + BOMB_IF_RC; + BOMB_IF((section.iv_size != + header.iv_section[SBE_XIP_SECTION_TOC].iv_size)); + + + // Make sure the .fixed section access compiles and seems to + // work. Modify an entry via the .fixed and verify it with normal TOC + // access. + + if (magicKey == SBE_SEEPROM_MAGIC) { + + BOMB_IF(0 != 0); + + exit(1); + + rc = sbe_xip_get_scalar(io_image, "proc_sbe_ex_dpll_initf_control", + &data); + BOMB_IF_RC; + //fixed = + //(ProcSbeFixed*)((unsigned long)io_image + SBE_XIP_FIXED_OFFSET); + //fixed->proc_sbe_ex_dpll_initf_control = 0xdeadbeefdeadc0deull; + rc = sbe_xip_get_scalar(io_image, "proc_sbe_ex_dpll_initf_control", + &data1); + BOMB_IF_RC; +#ifdef _BIG_ENDIAN + BOMB_IF(data1 != 0xdeadbeefdeadc0deull); +#else + BOMB_IF(data1 != 0xdec0addeefbeaddeull); +#endif + rc = sbe_xip_set_scalar(io_image, "proc_sbe_ex_dpll_initf_control", + data); + BOMB_IF_RC; + } + + // Temporarily "delete" the .toc section and try to get/set via the + // mini-TOC for .fixed, and make sure that we can't get things that + // are not in the mini-toc. + + tocSize = + ((SbeXipHeader*)io_image)->iv_section[SBE_XIP_SECTION_TOC].iv_size; + + ((SbeXipHeader*)io_image)->iv_section[SBE_XIP_SECTION_TOC].iv_size = + 0; + + rc = sbe_xip_get_scalar(io_image, "proc_sbe_ex_dpll_initf_control", + &data); + rc = sbe_xip_set_scalar(io_image, "proc_sbe_ex_dpll_initf_control", + 0xdeadbeef); + rc = sbe_xip_get_scalar(io_image, "proc_sbe_ex_dpll_initf_control", + &data1); + BOMB_IF(data1 != 0xdeadbeef); + rc = sbe_xip_set_scalar(io_image, "proc_sbe_ex_dpll_initf_control", + data); + BOMB_IF_RC; + + BOMB_IF(sbe_xip_find(io_image, "proc_sbe_ex_dpll_initf", 0) != + SBE_XIP_ITEM_NOT_FOUND); + + ((SbeXipHeader*)io_image)->iv_section[SBE_XIP_SECTION_TOC].iv_size = + tocSize; + + if (magicKey != SBE_SEEPROM_MAGIC) { + BOMB_IF(sbe_xip_find(io_image, "proc_sbe_ex_dpll_initf", 0) != 0); + } + + // Run the embedded delete and append tests. This assumes that the + // test image does not contain the .fit and .ffdc sections. We just + // append zeros here, we're mostly interested in whether we can handle + // errors and return the image back to its original state. + + BOMB_IF((deleteAppendImage = malloc(imageSize + 2000)) == 0); + memcpy(deleteAppendImage, io_image, imageSize); + + BOMB_IF(sbe_xip_append(deleteAppendImage, SBE_XIP_SECTION_FIT, + 0, 973, imageSize + 2000, 0) != 0); + BOMB_IF(sbe_xip_append(deleteAppendImage, SBE_XIP_SECTION_FFDC, + 0, 973, imageSize + 2000, 0) != 0); + +#ifdef DEBUG_SBE_XIP_IMAGE + printf("\nYou will see an expected warning below " + "about SBE_XIP_WOULD_OVERFLOW\n" + "It means the TEST is working (not failing)\n\n"); +#endif + + BOMB_IF(sbe_xip_append(deleteAppendImage, SBE_XIP_SECTION_FFDC, + 0, 973, imageSize + 2000, 0) == 0); + + BOMB_IF(sbe_xip_delete_section(deleteAppendImage, SBE_XIP_SECTION_FFDC) != 0); + BOMB_IF(sbe_xip_delete_section(deleteAppendImage, SBE_XIP_SECTION_FIT) != 0); + + memcpy(io_image, deleteAppendImage, imageSize); + + // Finally compare against the original + + BOMB_IF(memcmp(io_image, originalImage, imageSize)); + + } while (0); + + return rc; +} + + +/// Function: pairRingNameAndAddr() to be used w/sbe_xip_map_toc() +/// +/// Brief: Looks for address match for both base and override rings and +/// for multi-chiplet rings. Returns the ring name and other good +/// stuff in the PairingInfo structure upon a match. +/// +/// \param[in] i_image A pointer to an SBE-XIP image in host memory. +/// +/// \param[in] i_item A pointer to the "next" SbeXipItem in the TOC. +/// +/// \param[io] io_pairing A pointer to the structure, PairingInfo. +/// +/// Assumptions: +/// - On input, io_pairing contains +/// - address = the backPtr of the next ring block, +/// - vectorpos = the next vector position, starting from 0,1,2,..,31 and +/// which includes possible override pos. +/// - The TOC is then traversed and each TOC entry is put into i_item. +/// - The backPtr in io_pairing is kept constant until TOC has been exhausted. +/// - On output, io_pairing contains +/// - name = TOC name +/// - isvpd = whether it's a VPD or non-VPD ring +/// - overridable = whether it's an overridable ring +/// - override = whether it's a base or an override ring +/// - In general, we don't know if a ring is a base or an override of if it is a +/// multi-chiplet type. Thus, we first look for a match to the vector in +/// in position zero, then we try position one, then position two, ..., and up +/// to a max of position 31 (which would be an override for ex chiplet 0x1F). +/// +static int pairRingNameAndAddr( void *i_image, const SbeXipItem *i_item, void *io_pairing) +{ + int rc=0,rcLoc=-1; + SbeXipItem tocItem; + PairingInfo *pairingInfo; + RingIdList *ringIdList; + + SBE_XIP_ERROR_STRINGS(g_errorStrings); + + rcLoc = sbe_xip_find( i_image, i_item->iv_id, &tocItem); + if (rcLoc) { + fprintf( stderr, "sbe_xip_find() failed : %s\n", SBE_XIP_ERROR_STRING(g_errorStrings, rcLoc)); + rc = DIS_RING_NAME_ADDR_MATCH_FAILURE; + } + else { + pairingInfo = (PairingInfo*)io_pairing; + // Do a sanity check. + if (pairingInfo->vectorpos>31) { + fprintf( stderr, "vectorpos (=%i) must be between [0;31]\n",pairingInfo->vectorpos); + rc = DIS_RING_NAME_ADDR_MATCH_FAILURE; + } + // Check for match. + // - vectorpos is passed in such that first we look for base match, then for override + // or chiplet range match. + if (tocItem.iv_address == pairingInfo->address-8*pairingInfo->vectorpos && + tocItem.iv_id!=NULL ) { + pairingInfo->name = tocItem.iv_id; + rcLoc = get_vpd_ring_list_entry(pairingInfo->name,0,&ringIdList); + if (!rcLoc) { + // It is a VPD ring...and they never have overrides. + pairingInfo->isvpd = 1; + pairingInfo->overridable = 0; + } + else { + // It is a non-VPD ring...and they all have override capability. + pairingInfo->isvpd = 0; + pairingInfo->overridable = 1; + } + if (pairingInfo->vectorpos==0) + // This can only be a base match. + pairingInfo->override = 0; + else { + // This is not a base match. Investigating further if override. (Note, + // this includes a multi-dim vector with multi-dim override.) + if (pairingInfo->overridable && + 2*(pairingInfo->vectorpos/2)!=pairingInfo->vectorpos) + pairingInfo->override = 1; + else + pairingInfo->override = 0; + } + rc = DIS_RING_NAME_ADDR_MATCH_SUCCESS; + } + } + return rc; +} + +// this function is just defined out, because there is a future need. +#ifdef BLUBBER +/// Function: disassembleSection +/// +/// Brief: Disassembles a section and returns a pointer to a buffer that +/// contains the listing. +/// +/// \param[in] i_image A pointer to an SBE-XIP image in host memory. +/// +/// \param[in] i_argc Additional number of arguments beyond "dis" keyword. +/// +/// \param[in] i_argv Additional arguments beyond "dis" keyword. +/// +/// Assumptions: +/// +int disassembleSection(void *i_image, + int i_argc, + const char **i_argv) +{ + int rc=0, rcSet=0; + uint32_t rcCount=0; + char *disList=NULL; + uint32_t sizeSection=0, nextLinkOffsetBlock=0; + uint32_t sizeBlock=0, sizeData=0, sizeCode=0, sizeData2=0; + uint32_t sizeDisLine=0, sizeList=0, sizeListMax=0; + uint32_t offsetCode=0; + uint8_t typeRingsSection=0; // 0: RS4 1: Wiggle-Flip + uint8_t bSummary=0, bFoundInToc=0; + uint32_t sectionId; + uint64_t backPtr=0, fwdPtr=0; + PairingInfo pairingInfo; + const char *sectionName; + char *ringName; + uint32_t ringSeqNo=0; // Ring sequence location counter. + uint8_t vectorPos,overRidable; + void *nextBlock, *nextSection; + SbeXipHeader hostHeader; + SbeXipSection hostSection; + ImageInlineContext ctx; + ImageInlineDisassembly dis; + char lineDis[LISTING_STRING_SIZE]; + void *hostRs4Container; + uint32_t compressedBits=0, ringLength=0; + double compressionPct=0; + + if (i_argc != 1) { + fprintf(stderr, g_usage); + exit(1); + } + sectionName = i_argv[0]; + + // Determine SBE-XIP section ID from the section name, e.g. + // .ipl_text => SBE_XIP_SECTION_IPL_TEXT + // .text => SBE_XIP_SECTION_TEXT + // .rings => SBE_XIP_SECTION_RINGS + if (strcmp(sectionName, ".header")==0) + sectionId = SBE_XIP_SECTION_HEADER; + else + if (strcmp(sectionName, ".fixed")==0) + sectionId = SBE_XIP_SECTION_FIXED; + else + if (strcmp(sectionName, ".fixed_toc")==0) + sectionId = SBE_XIP_SECTION_FIXED_TOC; + else + if (strcmp(sectionName, ".ipl_text")==0) + sectionId = SBE_XIP_SECTION_IPL_TEXT; + else + if (strcmp(sectionName, ".ipl_data")==0) + sectionId = SBE_XIP_SECTION_IPL_DATA; + else + if (strcmp(sectionName, ".text")==0) + sectionId = SBE_XIP_SECTION_TEXT; + else + if (strcmp(sectionName, ".data")==0) + sectionId = SBE_XIP_SECTION_DATA; + else + if (strcmp(sectionName, ".toc")==0) + sectionId = SBE_XIP_SECTION_TOC; + else + if (strcmp(sectionName, ".strings")==0) + sectionId = SBE_XIP_SECTION_STRINGS; + else + if (strcmp(sectionName, ".pibmem0")==0) + sectionId = SBE_XIP_SECTION_PIBMEM0; + else + if (strcmp(sectionName, ".rings")==0) + sectionId = SBE_XIP_SECTION_RINGS; + else + if (strcmp(sectionName, ".rings_summary")==0) { + sectionId = SBE_XIP_SECTION_RINGS; + bSummary = 1; + } + else + if (strcmp(sectionName, ".dcrings")==0) + sectionId = SBE_XIP_SECTION_DCRINGS; + else + if (strcmp(sectionName, ".halt")==0) + sectionId = SBE_XIP_SECTION_HALT; + else + if (strcmp(sectionName, ".slw")==0) + sectionId = SBE_XIP_SECTION_SLW; + else + if (strcmp(sectionName, ".ffdc")==0) + sectionId = SBE_XIP_SECTION_FFDC; + else { + fprintf(stderr,"ERROR : %s is an invalid section name.\n",sectionName); + fprintf(stderr,"Valid
names for the 'dis' function are:\n"); + fprintf(stderr,"\t.header\n"); + fprintf(stderr,"\t.fixed\n"); + fprintf(stderr,"\t.fixed_toc\n"); + fprintf(stderr,"\t.ipl_text\n"); + fprintf(stderr,"\t.ipl_data\n"); + fprintf(stderr,"\t.text\n"); + fprintf(stderr,"\t.data\n"); + fprintf(stderr,"\t.toc\n"); + fprintf(stderr,"\t.strings\n"); + fprintf(stderr,"\t.pibmem0\n"); + fprintf(stderr,"\t.rings\n"); + fprintf(stderr,"\t.rings_summary\n"); + fprintf(stderr,"\t.dcrings\n"); + fprintf(stderr,"\t.halt\n"); + fprintf(stderr,"\t.slw\n"); + fprintf(stderr,"\t.ffdc\n"); + exit(1); + } + + // Get host header and section pointer. + // + sbe_xip_translate_header( &hostHeader, (SbeXipHeader*)i_image); + rc = sbe_xip_get_section( i_image, sectionId, &hostSection); + if (rc) { + fprintf( stderr, "sbe_xip_get_section() failed : %s\n", SBE_XIP_ERROR_STRING(g_errorStrings, rc)); + return SBE_XIP_DISASSEMBLER_ERROR; + } + sizeSection = hostSection.iv_size; + nextBlock = (void*)(hostSection.iv_offset + (uintptr_t)i_image); + nextSection = (void*)((uint64_t)nextBlock + (uint64_t)sizeSection); + + // Relocatable offset of section at hand. + nextLinkOffsetBlock = (uint32_t)hostHeader.iv_linkAddress + hostSection.iv_offset; + + // Allocate buffer to hold disassembled listing. (Start out with minimum 10k buffer size.) + // + if (sizeSection>10000) + sizeListMax = sizeSection; // Just to use something as an initial guess. + else + sizeListMax = 10000; + disList = (char*)malloc(sizeListMax); + if (disList==NULL) { + fprintf( stderr, "ERROR : malloc() failed.\n"); + fprintf( stderr, "\tMore info: %s\n", DIS_ERROR_STRING(g_errorStringsDis, DIS_MEMORY_ERROR)); + return SBE_XIP_DISASSEMBLER_ERROR; + } + *disList = '\0'; // Make sure the buffer is NULL terminated (though probably not needed.) + sizeList = 0; + + // Create context and point it to image section. + // + rc = image_inline_context_create( &ctx, + nextBlock, + sizeSection, + nextLinkOffsetBlock, + 0); + if (rc) { + fprintf( stderr, "ERROR : %s (rc=%i)\n",image_inline_error_strings[rc],rc); + fprintf( stderr, "\tMore info: %s\n", DIS_ERROR_STRING(g_errorStringsDis, DIS_DISASM_ERROR)); + return SBE_XIP_DISASSEMBLER_ERROR; + } + + while ((uint64_t)nextBlock<(uint64_t)nextSection) { + + // Disassemble sections based on their types and intents. + // + if (sectionId==SBE_XIP_SECTION_RINGS || sectionId==SBE_XIP_SECTION_DCRINGS) { + // Ring section (with a mix of data and code.) + // ...use BaseRingLayout structure to decode each ring block. + offsetCode = (uint32_t)myRev64(((BaseRingLayout*)nextBlock)->entryOffset); + sizeBlock = myRev32(((BaseRingLayout*)nextBlock)->sizeOfThis); + // ...determine ring type, either RS4 or Wiggle-flip. + if (offsetCode-(myRev32(((BaseRingLayout*)nextBlock)->sizeOfMeta)+3)/4*4>28) { + typeRingsSection = 0; // RS4 w/32-byte header. + sizeData2 = sizeBlock - offsetCode - ASM_RS4_LAUNCH_BUF_SIZE; + } + else + typeRingsSection = 1; // Wiggle-flip w/24-byte header. + // ...get the backPtr and fwdPtr and put at top of disasm listing. + backPtr = myRev64(((BaseRingLayout*)nextBlock)->backItemPtr); + sbe_xip_read_uint64(i_image, + backPtr, + &fwdPtr); + + // Calculate RS4 compression efficiency if RS4 rings. + if (typeRingsSection==0) { + hostRs4Container = (void*)( (uintptr_t)nextBlock + + offsetCode + ASM_RS4_LAUNCH_BUF_SIZE ); + compressedBits = myRev32(((CompressedScanData*)hostRs4Container)->iv_algorithmReserved) * 4; + ringLength = myRev32(((CompressedScanData*)hostRs4Container)->iv_length); + compressionPct = (double)compressedBits / (double)ringLength * 100.0; + } + + // + // Map over TOC or do a targeted search of FIXED_TOC to pair backPtr addr + // with ring name and override and/or vector position (i.e. multi-chiplet). + // + sbe_xip_get_section( i_image, SBE_XIP_SECTION_TOC, &hostSection); + if (hostSection.iv_offset) { + // TOC exists. + pairingInfo.address = backPtr; + // Search for pairing. First exhaust base position (pos=0), then next, then next, ... + for (pairingInfo.vectorpos=0;pairingInfo.vectorpos<32;pairingInfo.vectorpos++) { + rc = sbe_xip_map_toc( i_image, pairRingNameAndAddr, (void*)(&pairingInfo)); + if (rc) + break; + } + if (rc==DIS_RING_NAME_ADDR_MATCH_FAILURE) { + fprintf( stderr,"ERROR : Error associated with sbe_xip_map_toc().\n"); + fprintf( stderr, "\tMore info: %s\n", DIS_ERROR_STRING(g_errorStringsDis, DIS_RING_NAME_ADDR_MATCH_FAILURE)); + return SBE_XIP_DISASSEMBLER_ERROR; + } + ringSeqNo++; + if (rc==DIS_RING_NAME_ADDR_MATCH_SUCCESS) { + bFoundInToc = 1; + ringName = pairingInfo.name; // The ring name matched in pairRingNameAndAddr() + vectorPos = pairingInfo.vectorpos; // The vector position matched in pairRingNameAndAddr() + overRidable = pairingInfo.overridable; // Whether the ring supports on override ring. + if (pairingInfo.override) { + sizeDisLine = snprintf(lineDis,LISTING_STRING_SIZE, + "# ------------------------------\n# %i.\n# ringName = %s (override)\n# vectorPos = %i\n# overRidable = %i\n# backPtr = 0x%08x\n# fwdPtr = 0x%08x\n# Compressed Bits = %u\n# Ring Length Bits = %u\n# Compression = %0.2f%%\n", + ringSeqNo, ringName,vectorPos,overRidable,(uint32_t)backPtr,(uint32_t)fwdPtr,compressedBits,ringLength,compressionPct); + } + else { + sizeDisLine = snprintf(lineDis,LISTING_STRING_SIZE, + "# ------------------------------\n# %i.\n# ringName = %s (base)\n# vectorPos = %i\n# overRidable = %i\n# backPtr = 0x%08x\n# fwdPtr = 0x%08x\n# Compressed Bits = %u\n# Ring Length Bits = %u\n# Compression = %0.2f%%\n", + ringSeqNo,ringName,vectorPos,overRidable,(uint32_t)backPtr,(uint32_t)fwdPtr,compressedBits,ringLength,compressionPct); + } + } + else { + sizeDisLine = snprintf(lineDis,LISTING_STRING_SIZE, + "# ------------------------------\n# %i.\n# ringName = Not found (but TOC's available)\n# backPtr = 0x%08x\n# fwdPtr = 0x%08x\n", + ringSeqNo,(uint32_t)backPtr,(uint32_t)fwdPtr); + } + } + else { + // TOC doesn't exist. First try targeted search of MVPD ring names in FIXED_TOC. + bFoundInToc = 0; // If we find in fixed_toc, then change to 1. + // 2012-11-13: CMO TBD. Try using pairRingNameAndAddr by enabling a sequential + // traversing of each of the MVPD lists inside that function. You'll + // need to call pairRing manually from right here (or from a + // sbe_xip_search_fixed_toc()-like function). Maybe you can add a + // 4th arg to pairRing that is zero by default, meaning it is to be + // used by xip_map_toc(). But if non-zero, it is to be used in a + // traversing manner. Or you could add another member to the + // PairingInfo struct to indirectly pass this info to the function. + // You'd also need to pass two more arguments to get_vpd_ring_list_ + // entry() to indicate sequence number and the MVPD keyword. + // rc = pairRingNameAndAddr(); + // if (rc==DIS_RING_NAME_ADDR_MATCH_SUCCESS) { + // bFoundInToc = 1; + // // Do same as in TOC section above. + // break; + // } + // // OK, so ring name wasn't in TOC nor in FIXED_TOC. That happens if the ring + // // is a non-Mvpd ring and the TOC has been removed, such as in an IPL or + // // Seeprom image. + ringSeqNo++; + if (typeRingsSection==0) { + // RS4 header, which has override info + if (((Rs4RingLayout*)nextBlock)->override==0) { + sizeDisLine = snprintf(lineDis,LISTING_STRING_SIZE, + "# ------------------------------\n# %i.\n# ringName = Not available (base)\n# backPtr = 0x%08x\n# fwdPtr = 0x%08x\n# Compressed Bits = %u\n# Ring Length Bits = %u\n# Compression = %0.2f%%\n", + ringSeqNo,(uint32_t)backPtr,(uint32_t)fwdPtr,compressedBits,ringLength,compressionPct); + } + else { + sizeDisLine = snprintf(lineDis,LISTING_STRING_SIZE, + "# ------------------------------\n# %i.\n# ringName = Not available (override)\n# backPtr = 0x%08x\n# fwdPtr = 0x%08x\n# Compressed Bits = %u\n# Ring Length Bits = %u\n# Compression = %0.2f%%\n", + ringSeqNo,(uint32_t)backPtr,(uint32_t)fwdPtr,compressedBits,ringLength,compressionPct); + } + } + else { + // WF header, which doesn't have override info + sizeDisLine = snprintf(lineDis,LISTING_STRING_SIZE, + "# ------------------------------\n# %i.\n# ringName and override = Not available\n# backPtr = 0x%08x\n# fwdPtr = 0x%08x\n", + ringSeqNo,(uint32_t)backPtr,(uint32_t)fwdPtr); + } + } + sizeList = sizeList + sizeDisLine; + disList = strcat(disList,lineDis); + } + else if ( sectionId==SBE_XIP_SECTION_IPL_TEXT || + sectionId==SBE_XIP_SECTION_TEXT) { + // Sections that have only code. + offsetCode = 0; + sizeBlock = sizeSection; + } + else { + // Sections that have only data. + offsetCode = sizeSection; + sizeBlock = sizeSection; + } + sizeData = offsetCode; + sizeCode = sizeBlock - offsetCode - sizeData2; + + if (sectionId==SBE_XIP_SECTION_RINGS && bSummary) { + // + // Summarize rings section. + + if (typeRingsSection==0) { // RS4 header. + sizeDisLine = snprintf(lineDis,LISTING_STRING_SIZE, + "# ddLevel = 0x%02x\n# override= %i\n# sysPhase= %i\n# Block size= %i\n", + myRev32(((Rs4RingLayout*)nextBlock)->ddLevel), + ((Rs4RingLayout*)nextBlock)->override, + ((Rs4RingLayout*)nextBlock)->sysPhase, + sizeBlock); + } + else { // WF header. + if (bFoundInToc) { + sizeDisLine = snprintf(lineDis,LISTING_STRING_SIZE, + "# override= %i\n# Block size= %i\n", + pairingInfo.override, sizeBlock); + } + else { + sizeDisLine = snprintf(lineDis,LISTING_STRING_SIZE, + "# override= Not available\n# Block size= %i\n", + sizeBlock); + } + } + sizeList = sizeList + sizeDisLine; + disList = strcat(disList,lineDis); + // Readjust list buffer size, if needed. + if (sizeList > sizeListMax-1000) { + sizeListMax = 2*sizeListMax; + disList = (char*)realloc( (void*)(disList), sizeListMax); + } + + } + else { + // + // Do disassembly. + + // ...data disassembly + if (sizeData>0) { + ctx.options = IMAGE_INLINE_LISTING_MODE | IMAGE_INLINE_DISASSEMBLE_DATA; + do { + rc = image_inline_disassemble( &ctx, &dis); + sizeDisLine = snprintf(lineDis,LISTING_STRING_SIZE,"%s\n",dis.s); + sizeList = sizeList + sizeDisLine; + disList = strcat(disList,lineDis); + if (rc) { + rcSet = rcSet | 0x1; + sizeDisLine = snprintf(lineDis,LISTING_STRING_SIZE, + "WARNING: %s (rc=%i) -> Stopping disasm. Check code and sectionID=%i.\n", + image_inline_error_strings[rc],rc,sectionId); + sizeList = sizeList + sizeDisLine; + disList = strcat(disList,lineDis); + } + // Readjust list buffer size, if needed. + if (sizeList > sizeListMax-1000) { + sizeListMax = 2*sizeListMax; + disList = (char*)realloc( (void*)(disList), sizeListMax); + } + } while (rc==0 && ctx.lc0) { + ctx.options = IMAGE_INLINE_LISTING_MODE; + do { + rc = image_inline_disassemble( &ctx, &dis); + ctx.options = IMAGE_INLINE_LISTING_MODE; + sizeDisLine = snprintf(lineDis,LISTING_STRING_SIZE,"%s\n",dis.s); + sizeList = sizeList + sizeDisLine; + disList = strcat(disList,lineDis); + if (rc && rcCount<100) { + rcSet = rcSet | 0x2; + rcCount++; + if (sectionId==SBE_XIP_SECTION_RINGS) { + sizeDisLine = snprintf(lineDis,LISTING_STRING_SIZE, + "WARNING: %s (rc=%i) -> Trying data disasm mode. Check code, xyzRingLayout structures and image section.\n", + image_inline_error_strings[rc],rc); + } + else { + sizeDisLine = snprintf(lineDis,LISTING_STRING_SIZE, + "WARNING: %s (rc=%i) -> Trying data disasm mode.\n", + image_inline_error_strings[rc],rc); + } + sizeList = sizeList + sizeDisLine; + disList = strcat(disList,lineDis); + ctx.options = IMAGE_INLINE_LISTING_MODE | IMAGE_INLINE_DISASSEMBLE_DATA; + rc = 0; + } + else { + if (rc && rcCount>=1000) { + fprintf(stderr, "Too many disasm warnings. Check output listing.\n"); + fprintf( stderr, "\tMore info: %s\n", DIS_ERROR_STRING(g_errorStringsDis, DIS_TOO_MANY_DISASM_WARNINGS)); + return SBE_XIP_DISASSEMBLER_ERROR; + } + } + // Readjust list buffer size, if needed. + if (sizeList > sizeListMax-1000) { + sizeListMax = 2*sizeListMax; + disList = (char*)realloc( (void*)(disList), sizeListMax); + } + } while (rc==0 && ctx.lc0) { + ctx.options = IMAGE_INLINE_LISTING_MODE | IMAGE_INLINE_DISASSEMBLE_DATA; + do { + rc = image_inline_disassemble( &ctx, &dis); + sizeDisLine = snprintf(lineDis,LISTING_STRING_SIZE,"%s\n",dis.s); + sizeList = sizeList + sizeDisLine; + disList = strcat(disList,lineDis); + if (rc) { + rcSet = rcSet | 0x4; + sizeDisLine = snprintf(lineDis,LISTING_STRING_SIZE, + "WARNING: %s (rc=%i) -> Stopping disasm. Check code and sectionID=%i.\n", + image_inline_error_strings[rc],rc,sectionId); + sizeList = sizeList + sizeDisLine; + disList = strcat(disList,lineDis); + } + // Readjust list buffer size, if needed. + if (sizeList > sizeListMax-1000) { + sizeListMax = 2*sizeListMax; + disList = (char*)realloc( (void*)(disList), sizeListMax); + } + } while (rc==0 && ctx.lc