aboutsummaryrefslogtreecommitdiffstats
path: root/roms/skiboot/libpore
diff options
context:
space:
mode:
Diffstat (limited to 'roms/skiboot/libpore')
-rw-r--r--roms/skiboot/libpore/Makefile.inc11
-rw-r--r--roms/skiboot/libpore/fapi_sbe_common.H71
-rw-r--r--roms/skiboot/libpore/p10_cpu_reg_restore_instruction.H88
-rw-r--r--roms/skiboot/libpore/p10_hcd_header_defs.H152
-rw-r--r--roms/skiboot/libpore/p10_hcd_memmap_base.H463
-rw-r--r--roms/skiboot/libpore/p10_hcd_memmap_homer.H94
-rw-r--r--roms/skiboot/libpore/p10_hcd_memmap_occ_sram.H174
-rw-r--r--roms/skiboot/libpore/p10_hcode_image_defines.H462
-rw-r--r--roms/skiboot/libpore/p10_stop_api.C1816
-rw-r--r--roms/skiboot/libpore/p10_stop_api.H238
-rw-r--r--roms/skiboot/libpore/p10_stop_data_struct.H162
-rw-r--r--roms/skiboot/libpore/p10_stop_util.C190
-rw-r--r--roms/skiboot/libpore/p10_stop_util.H123
-rw-r--r--roms/skiboot/libpore/p8_delta_scan_rw.h468
-rw-r--r--roms/skiboot/libpore/p8_image_help_base.H125
-rw-r--r--roms/skiboot/libpore/p8_pore_api_custom.h141
-rw-r--r--roms/skiboot/libpore/p8_pore_table_gen_api.H440
-rw-r--r--roms/skiboot/libpore/p8_pore_table_gen_api_fixed.C846
-rw-r--r--roms/skiboot/libpore/p8_pore_table_static_data.c62
-rw-r--r--roms/skiboot/libpore/p9_cpu_reg_restore_instruction.H88
-rw-r--r--roms/skiboot/libpore/p9_hcd_header_defs.H152
-rw-r--r--roms/skiboot/libpore/p9_hcd_memmap_base.H558
-rw-r--r--roms/skiboot/libpore/p9_stop_api.C1743
-rw-r--r--roms/skiboot/libpore/p9_stop_api.H244
-rw-r--r--roms/skiboot/libpore/p9_stop_data_struct.H202
-rw-r--r--roms/skiboot/libpore/p9_stop_util.C193
-rw-r--r--roms/skiboot/libpore/p9_stop_util.H145
-rw-r--r--roms/skiboot/libpore/pgas.h1169
-rw-r--r--roms/skiboot/libpore/pore_inline.h883
-rw-r--r--roms/skiboot/libpore/pore_inline_assembler.c1509
-rw-r--r--roms/skiboot/libpore/sbe_xip_image.c2572
-rw-r--r--roms/skiboot/libpore/sbe_xip_image.h1789
32 files changed, 17373 insertions, 0 deletions
diff --git a/roms/skiboot/libpore/Makefile.inc b/roms/skiboot/libpore/Makefile.inc
new file mode 100644
index 000000000..06d9c8902
--- /dev/null
+++ b/roms/skiboot/libpore/Makefile.inc
@@ -0,0 +1,11 @@
+LIBPORE_SRCS = p8_pore_table_gen_api_fixed.C p9_stop_api.C p9_stop_util.C p10_stop_api.C p10_stop_util.C
+LIBPORE_SRCS += p8_pore_table_static_data.c sbe_xip_image.c pore_inline_assembler.c
+LIBPORE_OBJS_1 = $(LIBPORE_SRCS:%.c=%.o)
+LIBPORE_OBJS = $(LIBPORE_OBJS_1:%.C=%.o)
+SUBDIRS += libpore
+LIBPORE = libpore/built-in.a
+
+CFLAGS_SKIP_libpore/pore_inline_assembler.o=-Wsuggest-attribute=const
+
+$(LIBPORE): $(LIBPORE_OBJS:%=libpore/%)
+
diff --git a/roms/skiboot/libpore/fapi_sbe_common.H b/roms/skiboot/libpore/fapi_sbe_common.H
new file mode 100644
index 000000000..cf0e76f92
--- /dev/null
+++ b/roms/skiboot/libpore/fapi_sbe_common.H
@@ -0,0 +1,71 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/hwpf/hwp/include/fapi_sbe_common.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2012,2014 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __FAPI_SBE_COMMON_H
+#define __FAPI_SBE_COMMON_H
+
+// $Id: fapi_sbe_common.H,v 1.1 2012/04/16 23:55:37 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/fapi_sbe_common.H,v $
+//------------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2011
+// *! All Rights Reserved -- Property of IBM
+// *! *** ***
+//------------------------------------------------------------------------------
+// *! OWNER NAME : Email:
+
+/// \file fapi_sbe_common.H
+/// \brief Definitions common to FAPI and SBE procedures
+///
+/// Several preprocessor macros are required to have different definitions in
+/// C, C++ and SBE assembly procedures. These common forms are collected here.
+
+#if defined __ASSEMBLER__
+
+#define CONST_UINT8_T(name, expr) .set name, (expr)
+#define CONST_UINT32_T(name, expr) .set name, (expr)
+#define CONST_UINT64_T(name, expr) .set name, (expr)
+
+#define ULL(x) x
+
+#elif defined __cplusplus
+
+#include <stdint.h>
+
+#define CONST_UINT8_T(name, expr) const uint8_t name = (expr);
+#define CONST_UINT32_T(name, expr) const uint32_t name = (expr);
+#define CONST_UINT64_T(name, expr) const uint64_t name = (expr);
+
+#define ULL(x) x##ull
+
+#else // C code
+
+// CONST_UINT[8,3,64]_T() can't be used in C code/headers; Use
+//
+// #define <symbol> <value> [ or ULL(<value>) for 64-bit constants
+
+#define ULL(x) x##ull
+
+#endif // __ASSEMBLER__
+
+#endif // __FAPI_SBE_COMMON_H
diff --git a/roms/skiboot/libpore/p10_cpu_reg_restore_instruction.H b/roms/skiboot/libpore/p10_cpu_reg_restore_instruction.H
new file mode 100644
index 000000000..4da194d1e
--- /dev/null
+++ b/roms/skiboot/libpore/p10_cpu_reg_restore_instruction.H
@@ -0,0 +1,88 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p10/procedures/utils/stopreg/p10_cpu_reg_restore_instruction.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015,2019 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file p10_cpu_reg_restore_instruction.H
+/// @brief enumerates all the opcodes used for SPR restoration.
+///
+// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
+// *HWP Team : PM
+// *HWP Level : 2
+// *HWP Consumed by : HB:HYP
+
+#ifndef __REG_RESTORE_INSTRUCTION_H
+#define __REG_RESTORE_INSTRUCTION_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+
+namespace stopImageSection
+{
+#endif
+
+/**
+ * @brief enumerates opcodes for few instructions.
+ */
+enum
+{
+ ORI_OPCODE = 24,
+ RFI_OPCODE = 19,
+ RFI_CONST = 50,
+ MFMSR_CONST = 83,
+ ORIS_OPCODE = 25,
+ OPCODE_31 = 31,
+ XOR_CONST = 316,
+ RLDICR_OPCODE = 30,
+ RLDICR_CONST = 1,
+ MTSPR_CONST1 = 467,
+ MTMSRD_CONST1 = 178,
+ MR_R0_TO_R10 = 0x7c0a0378, //mr r10, r0
+ MR_R0_TO_R21 = 0x7c150378, //mr r21, r0
+ MR_R0_TO_R9 = 0x7c090378, //mr r9, r0
+ URMOR_CORRECTION = 0x7d397ba6,
+ MFSPR_CONST = 339,
+ BLR_INST = 0x4e800020,
+ MTSPR_BASE_OPCODE = 0x7c0003a6,
+ MFSPR_BASE_OPCODE = 0x7c0002a6,
+ ATTN_OPCODE = 0x00000200,
+ OPCODE_18 = 18,
+ SELF_SAVE_FUNC_ADD = 0x2300,
+ SELF_SAVE_OFFSET = 0x180,
+ SKIP_SPR_REST_INST = 0x4800001c, //b . +0x01c
+ MFLR_R30 = 0x7fc802a6,
+ SKIP_SPR_SELF_SAVE = 0x3bff0020, //addi r31 r31, 0x20
+ MTLR_INST = 0x7fc803a6 //mtlr r30
+};
+
+#ifdef __cplusplus
+} // namespace stopImageSection ends
+
+} // extern "C"
+#endif //__cplusplus
+
+#endif //__REG_RESTORE_INSTRUCTION_H
diff --git a/roms/skiboot/libpore/p10_hcd_header_defs.H b/roms/skiboot/libpore/p10_hcd_header_defs.H
new file mode 100644
index 000000000..d02a72524
--- /dev/null
+++ b/roms/skiboot/libpore/p10_hcd_header_defs.H
@@ -0,0 +1,152 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p10/procedures/hwp/lib/p10_hcd_header_defs.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016,2019 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+///
+/// @file p10_hcd_header_defs.H
+/// @brief defines header constants based on file types
+///
+/// This header contains those cpp manifest constants required for processing
+/// the linker scripts used to generate OCC code images. As these are used
+/// by linker scripts as well as by C++ code, these cannot be solely be put
+/// into a namespace. Prefixing these with the region name is the attempt
+/// to make these globally unique when this header is included in C++ code.
+///
+// *HWP HWP Owner: David Du <daviddu@us.ibm.com>
+// *HWP Backup HWP Owner: Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner: Prem Jha <premjha2@in.ibm.com>
+// *HWP Team: PM
+// *HWP Level: 2
+// *HWP Consumed by: PM
+//
+
+#ifndef __HCD_HEADER_DEFS_H__
+#define __HCD_HEADER_DEFS_H__
+
+/// Macros for generating an Hcode header section
+///
+/// The CPP macros HCD_HDR_UINTxx generate equivalent code depending on
+/// whether they are being called from assembler (where they actually
+/// create the header section data) or from C (where they specifiy a
+/// C-structure form of the contents of the header section.
+///
+/// In assembler each invocation also creates space in the header section
+
+#ifdef __ASSEMBLER__
+
+// *INDENT-OFF*
+ .macro hcd_header_uint64, symbol:req, value = 0
+ .global \symbol
+\symbol\():
+ .quad (\value)
+ .endm
+
+ .macro hcd_header_uint32, symbol:req, value = 0
+ .global \symbol
+ \symbol\():
+ .long (\value)
+ .endm
+
+ .macro hcd_header_uint16, symbol:req, value = 0
+ .global \symbol
+\symbol\():
+ .short (\value)
+ .endm
+
+ .macro hcd_header_uint8, symbol:req, value = 0
+ .global \symbol
+\symbol\():
+ .byte (\value)
+ .endm
+
+ .macro hcd_header_uint8_vec, symbol:req, number:req, value = 0
+ .global \symbol
+\symbol\():
+ .rept (\number)
+ .byte (\value)
+ .endr
+ .endm
+
+ .macro hcd_header_attn, symbol:req, number = 1
+ .global \symbol
+\symbol\():
+ .rept (\number)
+ .long 0x00000200
+ .endr
+ .endm
+
+ .macro hcd_header_attn_pad, align:req
+ .balignl (\align), 0x00000200
+ .endm
+
+ .macro hcd_header_pad, align:req
+ .balignl (\align), 0
+ .endm
+// *INDENT-ON*
+
+#define ULL(x) x
+#define HCD_CONST(name, expr) .set name, expr;
+#define HCD_CONST64(name, expr) .set name, expr;
+
+#define HCD_HDR_UINT64(symbol, value) hcd_header_uint64 symbol value
+#define HCD_HDR_UINT32(symbol, value) hcd_header_uint32 symbol value
+#define HCD_HDR_UINT16(symbol, value) hcd_header_uint16 symbol value
+#define HCD_HDR_UINT8(symbol, value) hcd_header_uint8 symbol value
+#define HCD_HDR_UINT8_VEC(symbol, number, value) hcd_header_uint8_vec symbol number value
+#define HCD_HDR_ATTN(symbol, number) hcd_header_attn symbol number
+#define HCD_HDR_ATTN_PAD(align) hcd_header_attn_pad align
+#define HCD_HDR_PAD(align) hcd_header_pad align
+
+#else // NOT __ASSEMBLER__
+
+#ifdef __LINKERSCRIPT__
+
+ #define ULL(x) x
+ #define POUND_DEFINE #define
+ #define HCD_CONST(name, expr) POUND_DEFINE name expr
+ #define HCD_CONST64(name, expr) POUND_DEFINE name expr
+
+#else
+
+ #define ULL(x) x##ull
+ #define HCD_CONST(name, expr) enum { name = expr };
+ #define HCD_CONST64(name, expr) enum { name = expr };
+
+ #define HCD_HDR_UINT64(symbol, value) uint64_t symbol
+ #define HCD_HDR_UINT32(symbol, value) uint32_t symbol
+ #define HCD_HDR_UINT16(symbol, value) uint16_t symbol
+ #define HCD_HDR_UINT8(symbol, value) uint8_t symbol
+ #define HCD_HDR_UINT8_VEC(symbol, number, value) uint8_t symbol[number]
+ #define HCD_HDR_ATTN(symbol, number) uint32_t symbol[number]
+ #define HCD_HDR_ATTN_PAD(align)
+ #define HCD_HDR_PAD(align)
+
+#endif // __LINKERSCRIPT__
+#endif // __ASSEMBLER__
+
+// Stringification
+
+#define STR_HELPER(x) #x
+#define STR(x) STR_HELPER(x)
+
+#endif // __HCD_HEADER_DEFS_H__
diff --git a/roms/skiboot/libpore/p10_hcd_memmap_base.H b/roms/skiboot/libpore/p10_hcd_memmap_base.H
new file mode 100644
index 000000000..4dac9c93b
--- /dev/null
+++ b/roms/skiboot/libpore/p10_hcd_memmap_base.H
@@ -0,0 +1,463 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p10/procedures/hwp/lib/p10_hcd_memmap_base.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2019,2020 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+///
+/// @file p10_hcd_memmap_base.H
+/// @brief defines region constants shared by different memory components.
+///
+
+// *HWP HWP Owner: David Du <daviddu@us.ibm.com>
+// *HWP Backup HWP Owner: Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner: Prem S Jha <premjha2@in.ibm.com>
+// *HWP Team: PM
+// *HWP Level: 2
+// *HWP Consumed by: PM:Hostboot:Phyp
+
+#ifndef __HCD_MEMMAP_BASE_H__
+#define __HCD_MEMMAP_BASE_H__
+
+#include <p10_hcd_header_defs.H>
+
+// -------------------------------------------------------------------
+// Note: There can be NO semicolons(";") at end of macros in this file
+// There can ONLY have HCD_CONST/HCD_CONST64 macros in this file
+// -------------------------------------------------------------------
+
+/// Image Magic Numbers
+
+HCD_CONST64(CPMR_MAGIC_NUMBER, ULL(0x43504d525f312e30)) // CPMR_1.0
+HCD_CONST64(QME_MAGIC_NUMBER , ULL(0x514d455f5f312e30)) // QME__1.0
+
+HCD_CONST64(XPMR_MAGIC_NUMBER, ULL(0x58504d525f312e30)) // XPMR_1.0
+HCD_CONST64(XGPE_MAGIC_NUMBER, ULL(0x584750455f312e30)) // XGPE_1.0
+
+HCD_CONST64(PPMR_MAGIC_NUMBER, ULL(0x50504d525f312e30)) // PPMR_1.0
+HCD_CONST64(PGPE_MAGIC_NUMBER, ULL(0x504750455F312E30)) // PGPE_1.0
+
+HCD_CONST(QME_BUILD_VERSION, 0x001) // QME__1.0
+HCD_CONST(XGPE_BUILD_VERSION, 0x001) // XGPE_1.0
+HCD_CONST(PGPE_BUILD_VERSION, 0x001) // PGPE_1.0
+
+
+HCD_CONST(CPMR_REGION_CHECK_WORD, (0x43504d52)) // CPMR
+HCD_CONST(SCOM_REST_MAGIC_WORD, (0x5343))//SC
+HCD_CONST(CPMR_BUILD_VER, 1)
+
+
+/// Size constants
+
+HCD_CONST(HALF_KB, 512)
+HCD_CONST(ONE_KB, 1024)
+HCD_CONST(HALF_MB, (1024 * 512))
+HCD_CONST(ONE_MB, (1024 * 1024))
+HCD_CONST(TWO_MB, (2 * 1024 * 1024))
+
+/// Memory constants
+
+HCD_CONST(QME_SRAM_SIZE, (64 * ONE_KB))
+
+HCD_CONST(HOMER_MEMORY_SIZE, (4 * ONE_MB))
+HCD_CONST(HOMER_OPMR_REGION_NUM, 0)
+HCD_CONST(HOMER_XPMR_REGION_NUM, 1)
+HCD_CONST(HOMER_CPMR_REGION_NUM, 2)
+HCD_CONST(HOMER_PPMR_REGION_NUM, 3)
+
+/// Chip constants
+HCD_CONST(OCC_HOST_AREA_SIZE, ONE_MB)
+
+HCD_CONST(MAX_THREADS_PER_CORE, 4)
+HCD_CONST(MAX_CORES_PER_CHIP, 32)
+
+HCD_CONST(MAX_QMES_PER_CHIP, 8)
+HCD_CONST(MAX_EXES_PER_CHIP, 16)
+
+HCD_CONST(MAX_QUADS_PER_CHIP, 8)
+HCD_CONST(MAX_CACHES_PER_CHIP, 32)
+
+HCD_CONST(MAX_CORES_PER_QME, 4)
+HCD_CONST(MAX_CORES_PER_EX, 2)
+
+HCD_CONST(MAX_QMES_PER_QUAD, 1)
+HCD_CONST(MAX_EXES_PER_QUAD, 2)
+HCD_CONST(MAX_CORES_PER_QUAD, 4)
+HCD_CONST(MAX_L3_PER_QUAD, 4)
+
+HCD_CONST(MAX_QUAD_ID_SUPPORTED, 7)
+HCD_CONST(MAX_CORE_ID_SUPPORTED, 31)
+HCD_CONST(MAX_THREAD_ID_SUPPORTED, 3)
+
+/// Image build constants
+
+HCD_CONST(HARDWARE_IMG_SIZE, ONE_MB)
+
+HCD_CONST(FUSED_CORE_MODE, 0xBB)
+HCD_CONST(NONFUSED_CORE_MODE, 0xAA)
+
+HCD_CONST(SELF_RESTORE_BLR_INST, 0x4e800020)
+HCD_CONST(CORE_RESTORE_PAD_OPCODE, 0x00000200) //ATTN Opcode
+
+HCD_CONST(SCOM_RESTORE_PAD_OPCODE, 0x00000000) //zero pads
+HCD_CONST(SCOM_RESTORE_ENTRY_SIZE, 12) //4B address,8B data
+
+HCD_CONST(QME_BLOCK_READ_LEN, 32)
+HCD_CONST(QME_BLK_SIZE_SHIFT, 0x05)
+
+HCD_CONST(RING_ALIGN_BOUNDARY, 0x08)
+HCD_CONST64(DARN_BAR_EN_POS, ULL(0x8000000000000000))
+
+//FFDC Region
+HCD_CONST(FFDC_REGION_XPMR_BASE_OFFSET, 0xE0000) //Offset wrt to XPMR base
+HCD_CONST(FFDC_REGION_SIZE, (80 * ONE_KB))
+//end offset of FFDC region wrt to XPMR base
+HCD_CONST(FFDC_REGION_XPMR_END_OFFSET, (FFDC_REGION_XPMR_BASE_OFFSET +
+ FFDC_REGION_SIZE ))
+//---------------------------------------------------------------------------------------
+
+//XPMR Header
+HCD_CONST(XGPE_BUILD_VER, 1)
+HCD_CONST(XPMR_BUILD_VER, 1)
+HCD_CONST(XPMR_HEADER_SIZE, 512)
+HCD_CONST(XGPE_INT_VECTOR_SIZE, 384)
+HCD_CONST(XGPE_HEADER_IMAGE_OFFSET, XGPE_INT_VECTOR_SIZE)
+HCD_CONST(XGPE_BOOT_COPIER_OFFSET, 512)
+HCD_CONST(XGPE_BOOT_COPIER_LENGTH, ONE_KB)
+HCD_CONST(XGPE_BOOT_LOADER_OFFSET,
+ XGPE_BOOT_COPIER_OFFSET + XGPE_BOOT_COPIER_LENGTH )
+HCD_CONST(XGPE_BOOT_LOADER_LENGTH, ONE_KB)
+HCD_CONST(XGPE_HCODE_OFFSET,
+ XGPE_BOOT_LOADER_OFFSET + XGPE_BOOT_LOADER_LENGTH )
+HCD_CONST(XGPE_SRAM_SIZE, (64 * ONE_KB))
+HCD_CONST(XGPE_HCODE_SIZE, (64 * ONE_KB))
+HCD_CONST(XPMR_BOOT_REGION, (XPMR_HEADER_SIZE + XGPE_BOOT_COPIER_LENGTH +
+ XGPE_BOOT_LOADER_LENGTH ))
+
+HCD_CONST(XGPE_HCODE_RESET_ADDR_VAL, 0x40)
+HCD_CONST(XGPE_DBG_PTR_AREA_SIZE, 64)
+
+HCD_CONST(XPMR_MAGIC_WORD_BYTE, 0x00)
+HCD_CONST(XPMR_BOOT_COPIER_OFFSET_BYTE, 0x08)
+HCD_CONST(XPMR_BOOT_LOADER_OFFSET_BYTE, 0x10)
+HCD_CONST(XPMR_BOOT_LOADER_LENGTH_BYTE, 0x14)
+HCD_CONST(XPMR_BUILD_DATE_BYTE, 0x18)
+HCD_CONST(XPMR_BUILD_VER_BYTE, 0x1c)
+HCD_CONST(XPMR_XGPE_HCODE_OFFSET_BYTE, 0x28)
+HCD_CONST(XPMR_XGPE_HCODE_LENGTH_BYTE, 0x2c)
+HCD_CONST(XPMR_XGPE_BOOT_PROG_CODE_BYTE, 0x30)
+HCD_CONST(XPMR_XGPE_SRAM_IMAGE_SIZE_BYTE, 0x34)
+HCD_CONST(XGPE_IMAGE_XPMR_OFFSET,
+ (XGPE_BOOT_LOADER_OFFSET + XGPE_BOOT_LOADER_LENGTH))
+
+//---------------------------------------------------------------------------------------
+
+/// CPMR Header
+
+HCD_CONST(CPMR_HOMER_OFFSET, (HOMER_CPMR_REGION_NUM* ONE_MB))
+HCD_CONST(CPMR_HEADER_SIZE, 256)
+
+HCD_CONST(CPMR_ATTN_WORD0_BYTE, 0x00)
+HCD_CONST(CPMR_ATTN_WORD1_BYTE, 0x04)
+HCD_CONST(CPMR_MAGIC_NUMBER_BYTE, 0x08)
+HCD_CONST(CPMR_BUILD_DATE_BYTE, 0x10)
+HCD_CONST(CPMR_BUILD_VER_BYTE, 0x14)
+HCD_CONST(CPMR_SELF_RESTORE_VER_BYTE, 0x1C)
+HCD_CONST(CPMR_STOP_API_VER_BYTE, 0x1D)
+HCD_CONST(CPMR_FUSED_CORE_FLAG, 0x1F)
+HCD_CONST(CPMR_QME_HCODE_OFFSET_BYTE, 0x20)
+HCD_CONST(CPMR_QME_HCODE_LENGTH_BYTE, 0x24)
+HCD_CONST(CPMR_CORE_COMMON_RING_OFFSET_BYTE, 0x28)
+HCD_CONST(CPMR_CORE_COMMON_RING_LENGTH_BYTE, 0x2C)
+HCD_CONST(CPMR_QME_LOCAL_PSTATE_OFFSET_BYTE, 0x30)
+HCD_CONST(CPMR_QME_LOCAL_PSTATE_LENGTH_BYTE, 0x34)
+HCD_CONST(CPMR_CORE_SPECIFIC_RING_OFFSET_BYTE, 0x38)
+HCD_CONST(CPMR_CORE_SPECIFIC_RING_LENGTH_BYTE, 0x3C)
+HCD_CONST(CPMR_CORE_SCOM_RESTORE_OFFSET_BYTE, 0x40)
+HCD_CONST(CPMR_CORE_SCOM_RESTORE_LENGTH_BYTE, 0x44)
+HCD_CONST(CPMR_SELF_RESTORE_OFFSET_BYTE, 0x48)
+HCD_CONST(CPMR_SELF_RESTORE_LENGTH_BYTE, 0x4C)
+HCD_CONST(CPMR_MAX_CORE_L2_SCOM_ENTRIES, 0x50)
+HCD_CONST(CPMR_MAX_QUAD_L3_SCOM_ENTRIES, 0x54)
+HCD_CONST(CPMR_MAX_CORE_L2_SCOM_OFFSET, 0x58)
+HCD_CONST(CPMR_MAX_CORE_L2_SCOM_LENGTH, 0x5C)
+HCD_CONST(CPMR_MAX_QUAD_SCOM_OFFSET, 0x60)
+HCD_CONST(CPMR_MAX_QUAD_SCOM_LENGTH, 0x64)
+
+/// Self Restore without SMF Support
+
+HCD_CONST(SELF_RESTORE_CPMR_OFFSET, CPMR_HEADER_SIZE)
+HCD_CONST(SELF_RESTORE_INT_SIZE, (8 * ONE_KB))
+HCD_CONST(SELF_RESTORE_FFDC_OFFSET, (224 * ONE_KB))
+HCD_CONST(SELF_RESTORE_FFDC_LENGTH, (32 * ONE_KB))
+HCD_CONST(SELF_RESTORE_FFDC_PER_CORE, 864)
+HCD_CONST(SELF_RESTORE_FFDC_PER_CORE_IN_HOMER, 1024)
+HCD_CONST(SELF_RESTORE_FFDC_PER_QUAD_IN_HOMER, (SELF_RESTORE_FFDC_PER_CORE_IN_HOMER * 4))
+HCD_CONST(SELF_RESTORE_FFDC_BLK_CNT, 27)
+
+// Self Restore Region With SMF Support
+HCD_CONST(SMF_THREAD_LAUNCHER_SIZE, 1024)
+HCD_CONST(SMF_SELF_RESTORE_CODE_SIZE,
+ (SELF_RESTORE_INT_SIZE + SMF_THREAD_LAUNCHER_SIZE))
+
+HCD_CONST(SMF_CORE_RESTORE_THREAD_AREA_SIZE, HALF_KB)
+HCD_CONST(SMF_SELF_SAVE_THREAD_AREA_SIZE, 256)
+HCD_CONST(SMF_CORE_RESTORE_CORE_AREA_SIZE, HALF_KB)
+HCD_CONST(SMF_CORE_SAVE_CORE_AREA_SIZE, HALF_KB)
+
+HCD_CONST(SMF_SELF_RESTORE_CORE_REGS_SIZE,
+ MAX_CORES_PER_CHIP * ((SMF_CORE_RESTORE_THREAD_AREA_SIZE* MAX_THREADS_PER_CORE ) +
+ (SMF_SELF_SAVE_THREAD_AREA_SIZE* MAX_THREADS_PER_CORE ) +
+ SMF_CORE_RESTORE_CORE_AREA_SIZE +
+ SMF_CORE_SAVE_CORE_AREA_SIZE ))
+
+HCD_CONST(SMF_SELF_RESTORE_SIZE_TOTAL,
+ (SMF_SELF_RESTORE_CODE_SIZE + SMF_SELF_RESTORE_CORE_REGS_SIZE))
+/// Core Scom
+
+HCD_CONST(SELF_SAVE_RESTORE_REGION_SIZE, (256 * ONE_KB))
+HCD_CONST(SCOM_RESTORE_CPMR_OFFSET, (256 * ONE_KB))
+HCD_CONST(SCOM_RESTORE_HOMER_OFFSET,
+ (SCOM_RESTORE_CPMR_OFFSET + CPMR_HOMER_OFFSET))
+
+HCD_CONST(MAX_CORE_SCOM_ENTRIES, 16)
+HCD_CONST(MAX_L2_SCOM_ENTRIES, 32)
+HCD_CONST(MAX_L3_SCOM_ENTRIES, 64)
+HCD_CONST(MAX_EQ_SCOM_ENTRIES, 16)
+HCD_CONST(MAX_SCOM_RESTORE_ENTRIES_PER_CORE, (MAX_CORE_SCOM_ENTRIES +
+ MAX_L2_SCOM_ENTRIES + MAX_L3_SCOM_ENTRIES +
+ MAX_EQ_SCOM_ENTRIES))
+
+
+HCD_CONST(SCOM_RESTORE_SIZE_PER_CORE,
+ (SCOM_RESTORE_ENTRY_SIZE* MAX_SCOM_RESTORE_ENTRIES_PER_CORE)) // 128 * 16
+HCD_CONST(SCOM_RESTORE_SIZE_PER_QME,
+ (SCOM_RESTORE_SIZE_PER_CORE* MAX_CORES_PER_QME)) // 128 * 16 * 4
+
+HCD_CONST(SCOM_RESTORE_SIZE_TOTAL, (96 * ONE_KB))
+
+HCD_CONST(SCOM_RESTORE_EL_AREA,
+ MAX_CORE_SCOM_ENTRIES* SCOM_RESTORE_ENTRY_SIZE)
+HCD_CONST(SCOM_RESTORE_L2_AREA,
+ MAX_L2_SCOM_ENTRIES* SCOM_RESTORE_ENTRY_SIZE)
+HCD_CONST(SCOM_RESTORE_L3_AREA,
+ MAX_L3_SCOM_ENTRIES* SCOM_RESTORE_ENTRY_SIZE)
+HCD_CONST(SCOM_RESTORE_EQ_AREA,
+ MAX_EQ_SCOM_ENTRIES* SCOM_RESTORE_ENTRY_SIZE)
+HCD_CONST(SCOM_RESTORE_VER, 1)
+HCD_CONST(SCOM_RESTORE_L2_CORE,
+ (MAX_CORE_SCOM_ENTRIES + MAX_L2_SCOM_ENTRIES))
+HCD_CONST(SCOM_RESTORE_L3_CACHE,
+ (MAX_EQ_SCOM_ENTRIES + MAX_L3_SCOM_ENTRIES))
+/// QME Image
+
+HCD_CONST(QME_IMAGE_CPMR_OFFSET, 0x58000) // assumes SCOMs take up the first 96KB of second 256KB
+//HCD_CONST(QME_IMAGE_SIZE, 0)
+HCD_CONST(QME_INT_VECTOR_SIZE, 384) // 0x180
+HCD_CONST(QME_HCODE_OFFSET, (SELF_SAVE_RESTORE_REGION_SIZE + SCOM_RESTORE_SIZE_TOTAL))
+
+/// QME Header
+
+HCD_CONST(QME_HEADER_CPMR_OFFSET,
+ (QME_IMAGE_CPMR_OFFSET + QME_INT_VECTOR_SIZE))
+HCD_CONST(QME_HEADER_IMAGE_OFFSET, QME_INT_VECTOR_SIZE)
+HCD_CONST(QME_HEADER_SIZE, 128) // 0x80, +0x180=0x200
+
+HCD_CONST(QME_MAGIC_NUMBER_BYTE, 0x00)
+HCD_CONST(QME_HCODE_OFFSET_BYTE, 0x08)
+HCD_CONST(QME_HCODE_LENGTH_BYTE, 0x0C)
+HCD_CONST(QME_COMMON_RING_OFFSET_BYTE, 0x10)
+HCD_CONST(QME_OVERRIDE_RING_OFFSET_BYTE, 0x14)
+HCD_CONST(QME_COMMON_RING_LENGTH_BYTE, 0x18)
+HCD_CONST(QME_LOCAL_PSTATE_OFFSET_BYTE, 0x1C)
+HCD_CONST(QME_LOCAL_PSTATE_LENGTH_BYTE, 0x20)
+HCD_CONST(QME_SPECIFIC_RING_OFFSET_BYTE, 0x24)
+HCD_CONST(QME_SPECIFIC_RING_LENGTH_BYTE, 0x28)
+HCD_CONST(QME_QUAD_SCOM_RESTORE_OFFSET_BYTE, 0x2C)
+HCD_CONST(QME_QUAD_SCOM_RESTORE_LENGTH_BYTE, 0x30)
+HCD_CONST(QME_ATTR_TANK_ADDRESS, 0x34)
+HCD_CONST(QME_LOCATION_ID_BYTE, 0x38)
+HCD_CONST(QME_TIME_BASE, 0x3C)
+HCD_CONST(QME_CPMR_HOMER_ADDRESS_BYTE, 0x40)
+
+HCD_CONST(QME_HCODE_OFF_IMAGE_OFFSET, (QME_HEADER_IMAGE_OFFSET + QME_HCODE_OFFSET_BYTE))
+HCD_CONST(QME_HCODE_LEN_IMAGE_OFFSET, (QME_HEADER_IMAGE_OFFSET + QME_HCODE_LENGTH_BYTE))
+
+/// QME Hcode
+
+HCD_CONST(QME_HCODE_IMAGE_OFFSET, (QME_INT_VECTOR_SIZE + QME_HEADER_SIZE)) // 0x200
+HCD_CONST(QME_HCODE_SIZE, (43 * ONE_KB))
+HCD_CONST(QME_COMMON_RING_SIZE, (5 * ONE_KB))
+HCD_CONST(QME_INST_RING_SIZE, (5 * ONE_KB))
+HCD_CONST(QME_DEBUG_PTRS_OFFSET, 0x200)
+HCD_CONST(QME_DEBUG_PTRS_SIZE, 0x10)
+HCD_CONST(QME_DUMP_PTRS_OFFSET, QME_DEBUG_PTRS_OFFSET + QME_DEBUG_PTRS_SIZE)
+HCD_CONST(QME_DUMP_PTRS_SIZE, 0x300)
+HCD_CONST(QME_ATTR_PTRS_OFFSET, QME_DUMP_PTRS_OFFSET + QME_DUMP_PTRS_SIZE)
+HCD_CONST(QME_INSTRUMENTATION_SIZE, HALF_KB)
+HCD_CONST(QME_SRAM_HCODE_OFFSET, 0)
+HCD_CONST(QME_OVERRIDE_RING_SIZE, (2 * ONE_KB))
+
+// QME Hcode + Core Scan + Pstate
+HCD_CONST(QME_REGION_SIZE, (128 * ONE_KB))
+
+// Debug
+
+HCD_CONST(CPMR_TRACE_REGION_OFFSET, (512 * ONE_KB))
+HCD_CONST(QME_TRACE_REGION_SIZE, (16 * ONE_KB))
+HCD_CONST(CPMR_TRACE_REGION_SIZE, (QME_TRACE_REGION_SIZE* MAX_QMES_PER_CHIP)) // 192K
+HCD_CONST(CPMR_DEBUG_REGION_OFFSET, CPMR_TRACE_REGION_OFFSET + CPMR_TRACE_REGION_SIZE)
+HCD_CONST(CPMR_DEBUG_REGION_SIZE, (64 * ONE_KB)) // 192K + 64K = 256K
+
+HCD_CONST(CACHE_CHIPLET_ID_MIN, 0x20 )
+HCD_CONST(CACHE_CHIPLET_ID_MAX, 0x27 )
+
+//---------------------------------------------------------------------------------------
+
+/// PPMR Header
+HCD_CONST(PPMR_BUILD_VERSION, 1)
+HCD_CONST(PPMR_HEADER_SIZE, 512)
+HCD_CONST(PGPE_INT_VECTOR_SIZE, 384)
+HCD_CONST(PGPE_HEADER_IMAGE_OFFSET, PGPE_INT_VECTOR_SIZE)
+HCD_CONST(PGPE_BOOT_COPIER_OFFSET, PPMR_HEADER_SIZE)
+HCD_CONST(PGPE_BOOT_COPIER_LENGTH, ONE_KB)
+HCD_CONST(PGPE_BOOT_LOADER_OFFSET,
+ (PGPE_BOOT_COPIER_OFFSET + PGPE_BOOT_COPIER_LENGTH) )
+
+HCD_CONST(PGPE_BOOT_LOADER_LENGTH, ONE_KB)
+HCD_CONST(PGPE_HCODE_OFFSET,
+ PGPE_BOOT_LOADER_OFFSET + PGPE_BOOT_LOADER_LENGTH )
+HCD_CONST(PPMR_HOMER_OFFSET, (HOMER_PPMR_REGION_NUM* ONE_MB))
+
+HCD_CONST(PPMR_MAGIC_NUMBER_BYTE, 0x00)
+HCD_CONST(PPMR_BOOT_COPIER_OFFSET_BYTE, 0x08)
+HCD_CONST(PPMR_BOOT_LOADER_OFFSET_BYTE, 0x10)
+HCD_CONST(PPMR_BOOT_LOADER_LENGTH_BYTE, 0x14)
+HCD_CONST(PPMR_BUILD_DATE_BYTE, 0x18)
+HCD_CONST(PPMR_BUILD_VER_BYTE, 0x1C)
+HCD_CONST(PPMR_PGPE_HCODE_OFFSET_BYTE, 0x28)
+HCD_CONST(PPMR_PGPE_HCODE_LENGTH_BYTE, 0x2C)
+HCD_CONST(PPMR_GLOBAL_PSTATE_OFFSET_BYTE, 0x30)
+HCD_CONST(PPMR_GLOBAL_PSTATE_LENGTH_BYTE, 0x34)
+HCD_CONST(PPMR_LOCAL_PSTATE_OFFSET_BYTE, 0x38)
+HCD_CONST(PPMR_LOCAL_PSTATE_LENGTH_BYTE, 0x3C)
+HCD_CONST(PPMR_OCC_PSTATE_OFFSET_BYTE, 0x40)
+HCD_CONST(PPMR_OCC_PSTATE_LENGTH_BYTE, 0x44)
+HCD_CONST(PPMR_PSTATE_TABLE_OFFSET_BYTE, 0x48)
+HCD_CONST(PPMR_PSTATE_TABLE_LENGTH_BYTE, 0x4C)
+HCD_CONST(PPMR_PGPE_SRAM_IMAGE_SIZE_BYTE, 0x50)
+HCD_CONST(PPMR_PGPE_BOOT_PROG_CODE_BYTE, 0x54)
+HCD_CONST(PPMR_WOF_TABLE_OFFSET, 0x58)
+HCD_CONST(PPMR_WOF_TABLE_LENGTH, 0x5C)
+HCD_CONST(PPMR_AUX_TASK_OFFSET, 0x60)
+HCD_CONST(PPMR_AUX_TASK_LENGTH, 0x64)
+HCD_CONST(PPMR_DEEP_OP_TRACE_OFFSET, 0x68)
+HCD_CONST(PPMR_DEEP_OP_TRACE_LENGTH, 0x6C)
+
+/// PGPE Boot
+
+HCD_CONST(PGPE_BOOT_COPIER_PPMR_OFFSET, PPMR_HEADER_SIZE)
+HCD_CONST(PGPE_BOOT_COPIER_SIZE, ONE_KB)
+
+HCD_CONST(PGPE_BOOT_LOADER_PPMR_OFFSET,
+ (PGPE_BOOT_COPIER_PPMR_OFFSET + PGPE_BOOT_COPIER_SIZE))
+HCD_CONST(PGPE_BOOT_LOADER_SIZE, ONE_KB)
+HCD_CONST(PGPE_BOOT_LOADER_RESET_ADDR_VAL, 0x40)
+HCD_CONST(XGPE_BOOT_LOADER_RESET_ADDR_VAL, PGPE_BOOT_LOADER_RESET_ADDR_VAL)
+
+HCD_CONST(PGPE_INSTRUMENTATION_SIZE, (2 * ONE_KB))
+/// PGPE Image
+HCD_CONST(PGPE_IMAGE_PPMR_OFFSET,
+ (PGPE_BOOT_LOADER_PPMR_OFFSET + PGPE_BOOT_LOADER_SIZE))
+
+HCD_CONST(PGPE_HCODE_RESET_ADDR_VAL, 0x40)
+HCD_CONST(PGPE_DBG_PTR_AREA_SIZE, 64)
+
+/// PGPE Header
+
+HCD_CONST(PGPE_HEADER_SIZE, 128)
+
+HCD_CONST(PGPE_MAGIC_NUMBER_BYTE, 0x00)
+HCD_CONST(PGPE_SYSTEM_RESET_ADDR_BYTE, 0x08)
+HCD_CONST(PGPE_SHARED_SRAM_ADDR_BYTE, 0x0C)
+HCD_CONST(PGPE_IVPR_ADDR_BYTE, 0x10)
+HCD_CONST(PGPE_SHARED_SRAM_LENGTH_BYTE, 0x14)
+HCD_CONST(PGPE_BUILD_DATE_BYTE, 0x18)
+HCD_CONST(PGPE_BUILD_VER_BYTE, 0x1C)
+HCD_CONST(PGPE_PGPE_FLAGS_BYTE, 0x20)
+HCD_CONST(PGPE_PGPE_TIMEBASE_HZ, 0x24)
+HCD_CONST(PGPE_GLOBAL_PSTATE_SRAM_ADDR_BYTE, 0x28)
+HCD_CONST(PGPE_HCODE_LENGTH_BYTE, 0x2C)
+HCD_CONST(PGPE_GLOBAL_PSTATE_MEM_OFFSET_BYTE, 0x30)
+HCD_CONST(PGPE_GLOBAL_PSTATE_PPB_SIZE_BYTE, 0x34)
+HCD_CONST(PGPE_GEN_PSTATE_TABLE_MEM_OFFSET_BYTE, 0x38)
+HCD_CONST(PGPE_GEN_PSTATE_TABLE_SIZE_BYTE, 0x3C)
+HCD_CONST(PGPE_OCC_PSTATE_TABLE_MEM_OFFSET_BYTE, 0x40)
+HCD_CONST(PGPE_OCC_PSTATE_TABLE_SIZE_BYTE, 0x44)
+HCD_CONST(PGPE_BEACON_ADDR_BYTE, 0x48)
+HCD_CONST(PGPE_RESERVE_1, 0x4C)
+HCD_CONST(PGPE_WOF_STATE_ADDR_BYTE, 0x50)
+HCD_CONST(PGPE_RESERVE_2, 0x54)
+HCD_CONST(PGPE_WOF_TABLE_ADDR_BYTE, 0x58)
+HCD_CONST(PGPE_WOF_TABLE_LENGTH_BYTE, 0x5C)
+HCD_CONST(PGPE_RESERVE_3, 0x60)
+HCD_CONST(PGPE_RESERVE_4, 0x64)
+HCD_CONST(PGPE_RESERVE_5, 0x68)
+HCD_CONST(PGPE_OP_TRACE_PTR_BYTE, 0x6C)
+HCD_CONST(PGPE_DEEP_OP_TRACE_MEM_ADDR_BYTE, 0x70)
+HCD_CONST(PGPE_DEEP_OP_TRACE_LENGTH_BYTE, 0x74)
+
+HCD_CONST(PGPE_RESET_ADDR_IMAGE_OFFSET, (PGPE_HEADER_IMAGE_OFFSET + PGPE_SYSTEM_RESET_ADDR_BYTE))
+HCD_CONST(PGPE_BUILD_DATE_IMAGE_OFFSET, (PGPE_HEADER_IMAGE_OFFSET + PGPE_BUILD_DATE_BYTE))
+HCD_CONST(PGPE_BUILD_VER_IMAGE_OFFSET, (PGPE_HEADER_IMAGE_OFFSET + PGPE_BUILD_VER_BYTE))
+
+//PPMR Misc
+HCD_CONST(PPMR_MEM_MASK, 0x80300000)
+
+/// PGPE Hcode
+HCD_CONST(PPMR_BOOT_REGION, (PPMR_HEADER_SIZE + PGPE_BOOT_COPIER_SIZE + PGPE_BOOT_LOADER_SIZE ))
+HCD_CONST(PGPE_SRAM_BOOT_REGION, (PPMR_HEADER_SIZE + PGPE_BOOT_LOADER_SIZE ))
+HCD_CONST(PGPE_GLOBAL_PSTATE_PARAM_BLOCK_SIZE, (6 * ONE_KB))
+HCD_CONST(PGPE_OCC_SHARED_SRAM_SIZE, (2 * ONE_KB))
+HCD_CONST(PGPE_DEBUG_PTRS_OFFSET, 0x200)
+HCD_CONST(PGPE_DEBUG_PTRS_SIZE, 0x24)
+
+
+/// Pstate Parameter Block + Pstate Table
+
+HCD_CONST(OCC_PSTATE_PARAM_BLOCK_PPMR_OFFSET, (128 * ONE_KB))
+HCD_CONST(OCC_PSTATE_PARAM_BLOCK_SIZE, (8 * ONE_KB)) // this is over allocated
+HCD_CONST(OCC_PSTATE_PARAM_BLOCK_REGION_SIZE, (16 * ONE_KB))
+
+HCD_CONST(PGPE_PSTATE_OUTPUT_TABLES_PPMR_OFFSET, (144 * ONE_KB))
+HCD_CONST(PGPE_PSTATE_OUTPUT_TABLES_SIZE, (8 * ONE_KB)) // this is over allocated
+HCD_CONST(PGPE_PSTATE_OUTPUT_TABLES_REGION_SIZE, (16 * ONE_KB))
+
+HCD_CONST(OCC_WOF_TABLES_PPMR_OFFSET, (768 * ONE_KB))
+HCD_CONST(OCC_WOF_TABLES_SIZE, (256 * ONE_KB))
+HCD_CONST(PPMR_RESERVE_PSTATE_TABLE_TO_WOF,
+ ( OCC_WOF_TABLES_PPMR_OFFSET - ( PGPE_PSTATE_OUTPUT_TABLES_PPMR_OFFSET + PGPE_PSTATE_OUTPUT_TABLES_REGION_SIZE ) ))
+
+HCD_CONST(WOF_TABLE_RESERVE,
+ OCC_WOF_TABLES_PPMR_OFFSET - (PGPE_PSTATE_OUTPUT_TABLES_PPMR_OFFSET + PGPE_PSTATE_OUTPUT_TABLES_REGION_SIZE))
+HCD_CONST(PGPE_AUX_TASK_SIZE, (2 * ONE_KB))
+
+#endif /* __HCD_MEMMAP_BASE_H__ */
diff --git a/roms/skiboot/libpore/p10_hcd_memmap_homer.H b/roms/skiboot/libpore/p10_hcd_memmap_homer.H
new file mode 100644
index 000000000..6338bf2dd
--- /dev/null
+++ b/roms/skiboot/libpore/p10_hcd_memmap_homer.H
@@ -0,0 +1,94 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p10/procedures/hwp/lib/p10_hcd_memmap_homer.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015,2019 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+///
+/// @file p9_hcd_memmap_homer.H
+/// @brief defines region constants of homer.
+///
+
+// *HWP HWP Owner: David Du <daviddu@us.ibm.com>
+// *HWP Backup HWP Owner: Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner: Prem S Jha <premjha2@in.ibm.com>
+// *HWP Team: PM
+// *HWP Level: 2
+// *HWP Consumed by: PM:Hostboot:Phyp
+
+#ifndef __P9_HCD_MEMMAP_HOMER_H__
+#define __P9_HCD_MEMMAP_HOMER_H__
+
+#include <p10_hcd_header_defs.H>
+#include <p10_hcd_memmap_base.H>
+
+// -------------------------------------------------------------------
+// Note: There can be NO semicolons(";") at end of macros in this file
+// There can ONLY have HCD_CONST/HCD_CONST64 macros in this file
+//--------------------------------------------------------------------
+
+/// HOMER
+
+HCD_CONST(HOMER_BASE_ADDR, 0x80000000)
+HCD_CONST(IMG_HDR_ALIGN_SIZE, 128)
+
+/// OPMR
+HCD_CONST(OPMR_REGION_SIZE, ONE_MB )
+
+
+/// XPMR
+HCD_CONST(XPMR_HOMER_OFFSET, (HOMER_XPMR_REGION_NUM* ONE_MB))
+HCD_CONST(HOMER_XPMR_BASE_ADDR, (HOMER_BASE_ADDR + (XPMR_HOMER_OFFSET)))
+HCD_CONST(HOMER_XPMR_HEADER_ADDR, HOMER_XPMR_BASE_ADDR)
+HCD_CONST(HOMER_XGPE_BOOT_COPIER_ADDR, (HOMER_XPMR_HEADER_ADDR + XPMR_HEADER_SIZE))
+HCD_CONST(XGPE_BOOT_COPIER_SIZE, (ONE_KB))
+HCD_CONST(HOMER_XGPE_BOOT_LOADER_OFFSET_ADDR,
+ (HOMER_XPMR_HEADER_ADDR + XPMR_BOOT_LOADER_OFFSET_BYTE))
+HCD_CONST(HOMER_XGPE_BOOT_LOADER_LENGTH_ADDR,
+ (HOMER_XPMR_HEADER_ADDR + XPMR_BOOT_LOADER_LENGTH_BYTE))
+
+/// CPMR
+
+HCD_CONST(HOMER_CPMR_BASE_ADDR, (HOMER_BASE_ADDR + (CPMR_HOMER_OFFSET)))
+HCD_CONST(HOMER_CPMR_HEADER_ADDR, HOMER_CPMR_BASE_ADDR)
+HCD_CONST(HOMER_CPMR_TRACE_ADDR, (HOMER_CPMR_BASE_ADDR + CPMR_TRACE_REGION_OFFSET))
+HCD_CONST(HOMER_CPMR_DEBUG_ADDR, (HOMER_CPMR_BASE_ADDR + CPMR_DEBUG_REGION_OFFSET))
+
+
+/// PPMR
+
+HCD_CONST(HOMER_PPMR_BASE_ADDR, (HOMER_BASE_ADDR + (PPMR_HOMER_OFFSET)))
+HCD_CONST(HOMER_PPMR_HEADER_ADDR, HOMER_PPMR_BASE_ADDR)
+HCD_CONST(HOMER_PGPE_BOOT_LOADER_OFFSET_ADDR,
+ (HOMER_PPMR_HEADER_ADDR + PPMR_BOOT_LOADER_OFFSET_BYTE))
+HCD_CONST(HOMER_PGPE_BOOT_LOADER_LENGTH_ADDR,
+ (HOMER_PPMR_HEADER_ADDR + PPMR_BOOT_LOADER_LENGTH_BYTE))
+HCD_CONST(HOMER_PGPE_BOOT_COPIER_ADDR,
+ (HOMER_PPMR_HEADER_ADDR + PPMR_HEADER_SIZE))
+
+HCD_CONST(HOMER_OCC_PSTATE_PARAM_BLOCK_ADDR,
+ (HOMER_PPMR_BASE_ADDR + OCC_PSTATE_PARAM_BLOCK_PPMR_OFFSET))
+HCD_CONST(HOMER_PGPE_PSTATE_OUTPUT_TABLES_ADDR,
+ (HOMER_PPMR_BASE_ADDR + PGPE_PSTATE_OUTPUT_TABLES_PPMR_OFFSET))
+HCD_CONST(HOMER_OCC_WOF_TABLES_ADDR,
+ (HOMER_PPMR_BASE_ADDR + OCC_WOF_TABLES_PPMR_OFFSET))
+
+#endif /* __P9_HCD_MEMMAP_HOMER_H__ */
diff --git a/roms/skiboot/libpore/p10_hcd_memmap_occ_sram.H b/roms/skiboot/libpore/p10_hcd_memmap_occ_sram.H
new file mode 100644
index 000000000..255748bc8
--- /dev/null
+++ b/roms/skiboot/libpore/p10_hcd_memmap_occ_sram.H
@@ -0,0 +1,174 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p10/procedures/hwp/lib/p10_hcd_memmap_occ_sram.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015,2020 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+///
+/// @file p10_hcd_memmap_occ_sram.H
+/// @brief defines region constants of occ sram.
+///
+
+// *HWP HWP Owner: David Du <daviddu@us.ibm.com>
+// *HWP Backup HWP Owner: Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner: Prem S Jha <premjha2@in.ibm.com>
+// *HWP Team: PM
+// *HWP Level: 2
+// *HWP Consumed by: HB, XGPE,PGPE
+
+#ifndef __HCD_MEMMAP_OCC_SRAM_H__
+#define __HCD_MEMMAP_OCC_SRAM_H__
+
+#include <p10_hcd_header_defs.H>
+#include <p10_hcd_memmap_base.H>
+
+// -------------------------------------------------------------------
+// Note: There can be NO semicolons(";") at end of macros in this file
+// There can ONLY have HCD_CONST/HCD_CONST64 macros in this file
+// -------------------------------------------------------------------
+
+/// OCC SRAM
+
+HCD_CONST(OCC_SRAM_BASE_ADDR, 0xFFF00000)
+HCD_CONST(GPE0_SRAM_BASE_ADDR, 0xFFF01000)
+HCD_CONST(GPE1_SRAM_BASE_ADDR, 0xFFF10000)
+HCD_CONST(PGPE_SRAM_BASE_ADDR, 0xFFF20000)
+HCD_CONST(XGPE_SRAM_BASE_ADDR, 0xFFF30000)
+HCD_CONST(OCC_SRAM_SIZE, ONE_MB)
+HCD_CONST(OCC_SRAM_END_ADDR, ( OCC_SRAM_BASE_ADDR + OCC_SRAM_SIZE))
+
+/// Base Addresses for various debug/trace regions in OCC SRAM
+HCD_CONST(OCC_SRAM_TRACE_BUF_BASE_ERR, 0xFFFB4000)
+HCD_CONST(OCC_SRAM_TRACE_BUF_BASE_INF, 0xFFFB6000)
+HCD_CONST(OCC_SRAM_TRACE_BUF_BASE_IMP, 0xFFFB8000)
+HCD_CONST(OCC_SRAM_TRACE_BUF_BASE_SSX_PTR, 0xFFF40824)
+HCD_CONST(OCC_SRAM_PGPE_REGION_SIZE, (64 * ONE_KB))
+HCD_CONST(OCC_SHARED_SRAM_ADDR_START,
+ ((PGPE_SRAM_BASE_ADDR + OCC_SRAM_PGPE_REGION_SIZE) - PGPE_OCC_SHARED_SRAM_SIZE))
+
+// Offset to trace buf ptr and trace buffer size from base
+HCD_CONST(GPE_DEBUG_PTR_OFFSET, 0x180)
+
+// Size of various traces regions in OCC SRAM
+HCD_CONST(OCC_SRAM_TRACE_BUF_SSX_SIZE_PTR, 0xFFF40828)
+HCD_CONST(OCC_SRAM_TRACE_BUF_ERR_SIZE, (8 * ONE_KB))
+HCD_CONST(OCC_SRAM_TRACE_BUF_INF_SIZE, (8 * ONE_KB))
+HCD_CONST(OCC_SRAM_TRACE_BUF_IMP_SIZE, (8 * ONE_KB))
+
+HCD_CONST(OCC_SRAM_IPC_REGION_SIZE, (4 * ONE_KB))
+HCD_CONST(OCC_SRAM_GPE0_REGION_SIZE, (60 * ONE_KB))
+HCD_CONST(OCC_SRAM_GPE1_REGION_SIZE, (64 * ONE_KB))
+HCD_CONST(OCC_SRAM_OCC_REGION_SIZE, (512 * ONE_KB))
+HCD_CONST(OCC_SRAM_XGPE_REGION_SIZE, (64 * ONE_KB))
+
+
+HCD_CONST(PPE_RESET_VECTOR, 0x40)
+//--------------------------------------------------------------------------------------
+
+/// PGPE Base
+
+HCD_CONST(OCC_SRAM_PGPE_BASE_ADDR, PGPE_SRAM_BASE_ADDR)
+HCD_CONST(OCC_SRAM_PGPE_END_ADDR,
+ (PGPE_SRAM_BASE_ADDR + OCC_SRAM_PGPE_REGION_SIZE))
+HCD_CONST(OCC_SRAM_PGPE_HCODE_RESET_ADDR,
+ (PGPE_SRAM_BASE_ADDR + PGPE_HCODE_RESET_ADDR_VAL))
+HCD_CONST(OCC_SRAM_PGPE_HEADER_ADDR,
+ (OCC_SRAM_PGPE_BASE_ADDR + PGPE_INT_VECTOR_SIZE))
+//PGPE image size is sum of various parts hence located here instead of p10_hcd_memmap_base.H
+HCD_CONST(PGPE_HCODE_SIZE, (OCC_SRAM_PGPE_REGION_SIZE - ( PGPE_OCC_SHARED_SRAM_SIZE +
+ PGPE_GLOBAL_PSTATE_PARAM_BLOCK_SIZE + PGPE_SRAM_BOOT_REGION )))
+HCD_CONST(PGPE_IMAGE_SIZE, (PGPE_HCODE_SIZE + PGPE_GLOBAL_PSTATE_PARAM_BLOCK_SIZE +
+ PGPE_OCC_SHARED_SRAM_SIZE + PGPE_SRAM_BOOT_REGION))
+HCD_CONST(PGPE_IMAGE_RESERVE_SIZE,
+ (OCC_PSTATE_PARAM_BLOCK_PPMR_OFFSET - PGPE_IMAGE_PPMR_OFFSET - PGPE_IMAGE_SIZE))
+
+
+/// PGPE Boot
+
+HCD_CONST(OCC_SRAM_PGPE_COPY_BOOT_LOADER_SIZE, ONE_KB)
+HCD_CONST(OCC_SRAM_PGPE_COPY_PPMR_HEADER_SIZE, 512)
+HCD_CONST(OCC_SRAM_PGPE_BOOT_LOADER_ADDR,
+ (OCC_SRAM_END_ADDR - OCC_SRAM_PGPE_COPY_BOOT_LOADER_SIZE))
+HCD_CONST(OCC_SRAM_PGPE_BOOT_LOADER_RESET_ADDR,
+ (OCC_SRAM_PGPE_BOOT_LOADER_ADDR + PGPE_BOOT_LOADER_RESET_ADDR_VAL))
+HCD_CONST(OCC_SRAM_PGPE_PPMR_HEADER_ADDR,
+ (OCC_SRAM_PGPE_BOOT_LOADER_ADDR - OCC_SRAM_PGPE_COPY_PPMR_HEADER_SIZE))
+HCD_CONST(OCC_SRAM_PGPE_OPTRACE_ADDR, OCC_SRAM_PGPE_BOOT_LOADER_ADDR)
+HCD_CONST(OCC_SRAM_PGPE_OPTRACE_SIZE, OCC_SRAM_PGPE_COPY_BOOT_LOADER_SIZE)
+
+/// PGPE Copy
+
+HCD_CONST(OCC_SRAM_PGPE_HCODE_OFFSET_ADDR,
+ (OCC_SRAM_PGPE_PPMR_HEADER_ADDR + PPMR_PGPE_HCODE_OFFSET_BYTE))
+HCD_CONST(OCC_SRAM_PGPE_HCODE_LENGTH_ADDR,
+ (OCC_SRAM_PGPE_PPMR_HEADER_ADDR + PPMR_PGPE_HCODE_LENGTH_BYTE))
+HCD_CONST(OCC_SRAM_PGPE_IMAGE_LENGTH_ADDR,
+ (OCC_SRAM_PGPE_PPMR_HEADER_ADDR + PPMR_PGPE_SRAM_IMAGE_SIZE_BYTE))
+
+// Misc constants used in PGPE boot loader and boot copier.
+HCD_CONST(PGPE_BOOT_COPY_SUCCESS, 0x42432d53 ) // ASCII code for BC-S
+HCD_CONST(PGPE_BOOT_COPIER_FAIL, 0x42432d46 ) // ASCII code for BC-F
+HCD_CONST(PGPE_BOOT_LOADER_SUCCESS, 0x424c2d53 ) // ASCII code for BL-S
+HCD_CONST(PGPE_BOOT_LOADER_FAIL, 0x424c2d46 ) // ASCII code for BL-F
+
+//--------------------------------------------------------------------------------------
+
+// Misc constants used in XGPE boot loader and boot copier.
+HCD_CONST(DIVDE_BY_8, 3)
+HCD_CONST(DOUBLE_WORD_SIZE, 8)
+HCD_CONST(XGPE_IMG_OFFSET_POS, 40)
+HCD_CONST(BOOT_COPIER_LEN_ZERO, 0)
+HCD_CONST(ENABLE_TRAP, 0)
+HCD_CONST(XGPE_BOOT_COPY_SUCCESS, 0x42432d53 ) // ASCII code for BC-S
+HCD_CONST(XGPE_BOOT_COPIER_FAIL, 0x42432d46 ) // ASCII code for BC-F
+HCD_CONST(XGPE_BOOT_LOADER_SUCCESS, 0x424c2d53 ) // ASCII code for BL-S
+HCD_CONST(XGPE_BOOT_LOADER_FAIL, 0x424c2d46 ) // ASCII code for BL-F
+
+/// XGPE Base
+HCD_CONST(OCC_SRAM_XGPE_SYSTEM_RESET_ADDR,
+ (XGPE_SRAM_BASE_ADDR + XGPE_HCODE_RESET_ADDR_VAL))
+HCD_CONST(OCC_SRAM_XGPE_IVPR_ADDR, XGPE_SRAM_BASE_ADDR)
+HCD_CONST(OCC_SRAM_XGPE_GPPB_ADDR,
+ (PGPE_SRAM_BASE_ADDR + PGPE_HEADER_IMAGE_OFFSET + PGPE_GLOBAL_PSTATE_SRAM_ADDR_BYTE))
+HCD_CONST(OCC_SRAM_XGPE_GPPB_LEN,
+ (PGPE_SRAM_BASE_ADDR + PGPE_HEADER_IMAGE_OFFSET + PGPE_GLOBAL_PSTATE_PPB_SIZE_BYTE))
+
+/// XGPE Boot
+HCD_CONST(OCC_SRAM_XGPE_COPY_BOOT_LOADER_SIZE, ONE_KB)
+HCD_CONST(OCC_SRAM_XGPE_COPY_XPMR_HEADER_SIZE, 512)
+HCD_CONST(OCC_SRAM_XGPE_BOOT_LOADER_ADDR,
+ (OCC_SRAM_END_ADDR - OCC_SRAM_XGPE_COPY_BOOT_LOADER_SIZE))
+HCD_CONST(OCC_SRAM_XGPE_BOOT_LOADER_RESET_ADDR,
+ (OCC_SRAM_XGPE_BOOT_LOADER_ADDR + XGPE_BOOT_LOADER_RESET_ADDR_VAL))
+HCD_CONST(OCC_SRAM_XGPE_XPMR_HEADER_ADDR,
+ (OCC_SRAM_XGPE_BOOT_LOADER_ADDR - OCC_SRAM_XGPE_COPY_XPMR_HEADER_SIZE))
+
+/// XGPE Copy
+HCD_CONST(OCC_SRAM_XGPE_HCODE_OFFSET_ADDR,
+ (OCC_SRAM_XGPE_XPMR_HEADER_ADDR + XPMR_XGPE_HCODE_OFFSET_BYTE))
+HCD_CONST(OCC_SRAM_XGPE_HCODE_LENGTH_ADDR,
+ (OCC_SRAM_XGPE_XPMR_HEADER_ADDR + XPMR_XGPE_HCODE_LENGTH_BYTE))
+HCD_CONST(OCC_SRAM_XGPE_IMAGE_LENGTH_ADDR,
+ (OCC_SRAM_XGPE_XPMR_HEADER_ADDR + XPMR_XGPE_SRAM_IMAGE_SIZE_BYTE))
+HCD_CONST(OCC_SRAM_XGPE_HCODE_RESET_ADDR,
+ (XGPE_SRAM_BASE_ADDR + XGPE_HCODE_RESET_ADDR_VAL))
+
+#endif /* __HCD_MEMMAP_OCC_SRAM_H__ */
diff --git a/roms/skiboot/libpore/p10_hcode_image_defines.H b/roms/skiboot/libpore/p10_hcode_image_defines.H
new file mode 100644
index 000000000..6a14cb241
--- /dev/null
+++ b/roms/skiboot/libpore/p10_hcode_image_defines.H
@@ -0,0 +1,462 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p10/procedures/hwp/lib/p10_hcode_image_defines.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2019,2020 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+///
+/// @file p10_hcode_image_defines.H
+/// @brief defines constants associated with hcode image build.
+///
+// *HWP HWP Owner: Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner: Prem S Jha <premjha2@in.ibm.com>
+// *HWP Team: PM
+// *HWP Level: 2
+// *HWP Consumed by: Hostboot: HBRT
+
+#ifndef __HW_IMG_DEFINE
+#define __HW_IMG_DEFINE
+
+#include <p10_hcd_header_defs.H>
+#include <p10_hcd_memmap_base.H>
+#include <p10_hcd_memmap_homer.H>
+#include <p10_hcd_memmap_occ_sram.H>
+
+//--------------------------------------------------------------------------
+// local structs and constants
+// -------------------------------------------------------------------------
+#ifndef __ASSEMBLER__
+#ifdef __cplusplus
+#ifndef __PPE_PLAT
+
+#define IMG_HDR_ALIGN_SIZE 32
+
+namespace hcodeImageBuild
+{
+#endif //__PPE_PLAT
+#endif //__cplusplus
+#endif //__ASSEMBLER__
+
+/**
+ * CPMR Header
+ *
+ * This header is only consumed by Hcode Image Build and
+ * lab tools, not by PPE code. It is generated with assembler
+ * primitives during QME build and placed in HOMER by
+ * Hcode Image Build.
+ */
+
+#ifdef __ASSEMBLER__
+.macro .cpmr_header
+.section ".cpmr" , "aw"
+.balign 8
+#else
+typedef struct
+{
+#endif
+HCD_HDR_ATTN ( iv_attnOpcodes, 2);
+HCD_HDR_UINT64( iv_cpmrMagicWord, CPMR_MAGIC_NUMBER);
+HCD_HDR_UINT32( iv_buildDate, 0);
+HCD_HDR_UINT32( iv_version, 0);
+HCD_HDR_UINT8_VEC (iv_reserveFlags, 4, 0);
+HCD_HDR_UINT8 ( iv_selfRestoreVer, 0);
+HCD_HDR_UINT8 ( iv_stopApiVer, 0);
+HCD_HDR_UINT8 ( iv_urmorFix, 0);
+HCD_HDR_UINT8 ( iv_fusedMode, 0);
+HCD_HDR_UINT32( iv_qmeImgOffset, 0);
+HCD_HDR_UINT32( iv_qmeImgLength, 0);
+HCD_HDR_UINT32( iv_commonRingOffset, 0);
+HCD_HDR_UINT32( iv_commonRingLength, 0);
+HCD_HDR_UINT32( iv_localPstateOffset, 0);
+HCD_HDR_UINT32( iv_localPstateLength, 0);
+HCD_HDR_UINT32( iv_specRingOffset, 0);
+HCD_HDR_UINT32( iv_specRingLength, 0);
+HCD_HDR_UINT32( iv_scomRestoreOffset, 0);
+HCD_HDR_UINT32( iv_scomRestoreLength, 0);
+HCD_HDR_UINT32( iv_selfRestoreOffset, 0);
+HCD_HDR_UINT32( iv_selfRestoreLength, 0);
+HCD_HDR_UINT32( iv_maxCoreL2ScomEntry, 0);
+HCD_HDR_UINT32( iv_maxEqL3ScomEntry, 0);
+HCD_HDR_UINT32( iv_coreL2ScomOffset, 0);
+HCD_HDR_UINT32( iv_coreL2ScomLength, 0);
+HCD_HDR_UINT32( iv_eqL3ScomOffset, 0);
+HCD_HDR_UINT32( iv_eqL3ScomLength, 0);
+HCD_HDR_PAD(CPMR_HEADER_SIZE);
+#ifdef __ASSEMBLER__
+.endm
+#else
+} __attribute__((packed, aligned(256))) CpmrHeader_t;
+#endif
+
+/**
+ * QME Header
+ *
+ * The QME header is loaded in the QME SRAM so it is "tight" (little extra space)
+ * Thus, this "structure" is NOT padded to a specific size and is limited to
+ * 64B. Also, structure member names are preceded with "g_" as these becoming
+ * global variables in the QME Hcode.
+ */
+#ifdef __ASSEMBLER__
+.macro .qme_header
+.section ".qme_image_header" , "aw"
+.balign 8
+#else
+typedef struct
+{
+#endif
+HCD_HDR_UINT64( g_qme_magic_number, QME_MAGIC_NUMBER );
+HCD_HDR_UINT32( g_qme_hcode_offset, 0 );
+HCD_HDR_UINT32( g_qme_hcode_length, 0 );
+HCD_HDR_UINT32( g_qme_common_ring_offset, 0 );
+HCD_HDR_UINT32( g_qme_cmn_ring_ovrd_offset, 0 );
+HCD_HDR_UINT32( g_qme_common_ring_length, 0 );
+HCD_HDR_UINT32( g_qme_pstate_region_offset, 0 );
+HCD_HDR_UINT32( g_qme_pstate_region_length, 0 );
+HCD_HDR_UINT32( g_qme_inst_spec_ring_offset, 0 );
+HCD_HDR_UINT32( g_qme_max_spec_ring_length, 0 );
+HCD_HDR_UINT32( g_qme_scom_offset, 0 );
+HCD_HDR_UINT32( g_qme_scom_length, 0 );
+HCD_HDR_UINT32( g_qme_attr_tank_address, 0 );
+HCD_HDR_UINT16( g_qme_location_id, 0 );
+HCD_HDR_UINT16( g_qme_reserved , 0 );
+HCD_HDR_UINT32( g_qme_timebase_hz, 0 ); //Retain next field at 8B boundary
+HCD_HDR_UINT64( g_qme_cpmr_PhyAddr, 0 );
+HCD_HDR_UINT64( g_qme_unsec_cpmr_PhyAddr, 0 );
+HCD_HDR_UINT32( g_qme_custom_length, 0 );
+HCD_HDR_UINT32( g_qme_elog_addr, 0 );
+HCD_HDR_PAD(IMG_HDR_ALIGN_SIZE);
+#ifdef __ASSEMBLER__
+.endm
+#else
+//QME Header size is 96B
+} __attribute__((packed, aligned(32))) QmeHeader_t;
+#endif
+
+#ifndef __ASSEMBLER__
+
+typedef struct QMEImageFlags
+{
+ uint32_t fused_mode : 1;
+ uint32_t reserved0 : 31;
+} QMEImageFlags_t;
+
+#endif //__ASSEMBLER__
+
+#ifdef __ASSEMBLER__
+.macro .ppmr_header
+.section ".ppmr" , "aw"
+.balign 8
+#else
+typedef struct
+{
+#endif
+HCD_HDR_UINT64( iv_ppmrMagicWord, PPMR_MAGIC_NUMBER);
+HCD_HDR_UINT32( iv_bootCopierOffset, 0);
+HCD_HDR_UINT32( iv_reserved1, 0);
+HCD_HDR_UINT32( iv_bootLoaderOffset, 0);
+HCD_HDR_UINT32( iv_bootLoaderLength, 0);
+HCD_HDR_UINT32( iv_buildDate, 0);
+HCD_HDR_UINT32( iv_buildVer, 0);
+HCD_HDR_UINT64( iv_reserved2, 0);
+HCD_HDR_UINT32( iv_hcodeOffset, 0);
+HCD_HDR_UINT32( iv_hcodeLength, 0);
+HCD_HDR_UINT32( iv_gpspbOffset, 0);
+HCD_HDR_UINT32( iv_gpspbLength, 0);
+HCD_HDR_UINT32( iv_lpspbOffset, 0);
+HCD_HDR_UINT32( iv_lpspbLength, 0);
+HCD_HDR_UINT32( iv_opspbOffset, 0);
+HCD_HDR_UINT32( iv_opspbLength, 0);
+HCD_HDR_UINT32( iv_pstateOffset, 0);
+HCD_HDR_UINT32( iv_pstateLength, 0);
+HCD_HDR_UINT32( iv_sramSize, 0);
+HCD_HDR_UINT32( iv_progCode, 0);
+HCD_HDR_UINT32( iv_wofTableOffset, 0);
+HCD_HDR_UINT32( iv_wofTableLength, 0);
+HCD_HDR_UINT32( iv_deepOptraceOffset, 0);
+HCD_HDR_UINT32( iv_deepOptraceLength, 0);
+
+#ifdef __ASSEMBLER__
+.endm
+#else
+} __attribute__((packed, aligned(32))) PpmrHeader_t;
+#endif
+
+#ifdef __ASSEMBLER__
+.macro .pgpe_header
+.section ".pgpe_hdr" , "aw"
+.balign 8
+#else
+typedef struct
+{
+#endif
+HCD_HDR_UINT64( g_pgpe_magicWord, PGPE_MAGIC_NUMBER);
+HCD_HDR_UINT32( g_pgpe_sysResetAddress, 0);
+HCD_HDR_UINT32( g_pgpe_sharedSramAddress, 0);
+HCD_HDR_UINT32( g_pgpe_ivprAddress, 0);
+HCD_HDR_UINT32( g_pgpe_sharedLength, 0);
+HCD_HDR_UINT32( g_pgpe_buildDate, 0);
+HCD_HDR_UINT32( g_pgpe_buildVer, 0);
+HCD_HDR_UINT32( g_pgpe_reserved0, 0);
+HCD_HDR_UINT32( g_pgpe_timeBaseHz, 0);
+HCD_HDR_UINT32( g_pgpe_gpspbSramAddress, 0);
+HCD_HDR_UINT32( g_pgpe_hcodeLength, 0);
+HCD_HDR_UINT32( g_pgpe_gpspbMemOffset, 0);
+HCD_HDR_UINT32( g_pgpe_gpspbMemLength, 0);
+HCD_HDR_UINT32( g_pgpe_genPsTableMemOffset, 0);
+HCD_HDR_UINT32( g_pgpe_genPsTableMemLength, 0);
+HCD_HDR_UINT32( g_pgpe_opspbTableAddress, 0);
+HCD_HDR_UINT32( g_pgpe_opspbTableLength, 0);
+HCD_HDR_UINT32( g_pgpe_beaconAddress, 0);
+HCD_HDR_UINT32( g_pgpe_reserved1, 0);
+HCD_HDR_UINT32( g_pgpe_pgpeWofStateAddress, 0);
+HCD_HDR_UINT32( g_pgpe_reserved2, 0);
+HCD_HDR_UINT32( g_pgpe_wofTableAddress, 0);
+HCD_HDR_UINT32( g_pgpe_wofTableLength, 0);
+HCD_HDR_UINT32( g_pgpe_reserved3, 0);
+HCD_HDR_UINT32( g_pgpe_reserved4, 0);
+HCD_HDR_UINT32( g_pgpe_reserved5, 0);
+HCD_HDR_UINT32( g_pgpe_opTracePtr, 0);
+HCD_HDR_UINT32( g_pgpe_deepOpTraceMemAddress, 0);
+HCD_HDR_UINT32( g_pgpe_deepOpTraceLength, 0);
+#ifdef __ASSEMBLER__
+.endm
+#else
+} __attribute__((packed, aligned(32))) PgpeHeader_t;
+#endif
+
+#ifdef __ASSEMBLER__
+.macro .xpmr_hdr
+.section ".xpmr" , "aw"
+.balign 8
+#else
+typedef struct
+{
+#endif
+HCD_HDR_UINT64( iv_xpmrMagicWord, XPMR_MAGIC_NUMBER);
+HCD_HDR_UINT32( iv_bootCopierOffset, 0);
+HCD_HDR_UINT32( iv_reserve1, 0);
+HCD_HDR_UINT32( iv_bootLoaderOffset, 0);
+HCD_HDR_UINT32( iv_bootLoaderLength, 0);
+HCD_HDR_UINT32( iv_buildDate, 0);
+HCD_HDR_UINT32( iv_version, 0);
+HCD_HDR_UINT32( iv_reserve2, 0);
+HCD_HDR_UINT32( iv_reserve3, 0);
+HCD_HDR_UINT32( iv_xgpeHcodeOffset, 0);
+HCD_HDR_UINT32( iv_xgpeHcodeLength, 0);
+HCD_HDR_UINT32( iv_xgpeBootProgCode, 0);
+HCD_HDR_UINT32( iv_xgpeSramSize, 0);
+HCD_HDR_PAD(XPMR_HEADER_SIZE);
+#ifdef __ASSEMBLER__
+.endm
+#else
+} __attribute__((packed, aligned(512))) XpmrHeader_t;
+#endif
+
+#ifdef __ASSEMBLER__
+.macro .xgpe_header
+.section ".xgpe_header" , "aw"
+.balign 8
+#else
+typedef struct
+{
+#endif
+HCD_HDR_UINT64( g_xgpe_magicWord, XGPE_MAGIC_NUMBER);
+HCD_HDR_UINT32( g_xgpe_sysResetAddress, 0 ); //FIXME need to add correct address
+HCD_HDR_UINT32( g_xgpe_sharedSramAddress, 0 ); //FIXME need to add correct address
+HCD_HDR_UINT32( g_xgpe_ivprAddress, 0 ); //FIXME need to add correct address
+HCD_HDR_UINT32( g_xgpe_sharedSramLength, 0 );
+HCD_HDR_UINT32( g_xgpe_buildDate, 0 );
+HCD_HDR_UINT32( g_xgpe_buildVer, 0 );
+HCD_HDR_UINT16( g_xgpe_xgpeFlags, 0 );
+HCD_HDR_UINT16( g_xgpe_reserve1, 0 );
+HCD_HDR_UINT32( g_xgpe_timeBaseHz, 0 );
+HCD_HDR_UINT32( g_xgpe_gpspbSramAddress, 0 );
+HCD_HDR_UINT32( g_xgpe_hcodeLength, 0 );
+HCD_HDR_UINT32( g_xgpe_reserve2, 0 );
+HCD_HDR_UINT32( g_xgpe_gpspbLength, 0 );
+HCD_HDR_UINT32( g_xgpe_coreThrottleAssertCnt, 0 );
+HCD_HDR_UINT32( g_xgpe_coreThrottleDeAssertCnt, 0 );
+HCD_HDR_UINT32( g_xgpe_charactControls, 0 );
+HCD_HDR_UINT32( g_xgpe_xgpeOpTracePointer, 0 );
+HCD_HDR_UINT32( g_xgpe_xgpeDeepOpTraceMemAddr, 0 );
+HCD_HDR_UINT32( g_xgpe_xgpeDeepOpTraceLength, 0 );
+HCD_HDR_PAD(IMG_HDR_ALIGN_SIZE);
+#ifdef __ASSEMBLER__
+.endm
+#else
+} __attribute__((packed, aligned(32))) XgpeHeader_t;
+#endif
+
+#ifndef __ASSEMBLER__
+
+/**
+ * @brief enumerates all return codes associated with hcode image build.
+ */
+enum ImgBldRetCode_t
+{
+ IMG_BUILD_SUCCESS = 0,
+ BUILD_FAIL_XGPE_IMAGE = 1,
+ BUILD_FAIL_SELF_REST_IMAGE = 2,
+ BUILD_FAIL_QME_IMAGE = 3,
+ BUILD_FAIL_PGPE_IMAGE = 4,
+ BUILD_FAIL_XGPE_QPMR = 5,
+ BUILD_FAIL_XGPE_BL1 = 6,
+ BUILD_FAIL_XGPE_BL2 = 7,
+ BUILD_FAIL_XGPE_INT_VECT = 8,
+ BUILD_FAIL_XGPE_HDR = 9,
+ BUILD_FAIL_XGPE_HCODE = 10,
+ BUILD_FAIL_XGPE_CMN_RINGS = 11,
+ BUILD_FAIL_XGPE_SPEC_RINGS = 12,
+ BUILD_FAIL_CPMR_HDR = 13,
+ BUILD_FAIL_SRESET_HNDLR = 14,
+ BUILD_FAIL_THRD_LAUNCHER = 15,
+ BUILD_FAIL_SPR_RESTORE = 16,
+ BUILD_FAIL_SCOM_RESTORE = 17,
+ BUILD_FAIL_QME_IMG_HDR = 18,
+ BUILD_FAIL_QME_HCODE = 19,
+ BUILD_FAIL_CMN_RINGS = 20,
+ BUILD_FAIL_QME_QUAD_PSTATE = 21,
+ BUILD_FAIL_SPEC_RINGS = 22,
+ BUILD_FAIL_INT_VECT = 23,
+ BUILD_FAIL_PGPE_BL1 = 24,
+ BUILD_FAIL_PGPE_BL2 = 25,
+ BUILD_FAIL_PGPE_HCODE = 26,
+ BUILD_FAIL_OVERRIDE = 27,
+ BUILD_SEC_SIZE_OVERFLOW = 28,
+ BUILD_FAIL_INVALID_SECTN = 29,
+ BUILD_FAIL_RING_EXTRACTN = 30,
+ QME_SRAM_IMG_SIZE_ERR = 31,
+ XGPE_SRAM_IMG_SIZE_ERR = 32,
+ PGPE_SRAM_IMG_SIZE_ERR = 33,
+ BUILD_FAIL_PGPE_PPMR = 34,
+ BUILD_FAIL_XIP_CUST_ERR = 35,
+ BUILD_ERR_INTERNAL = 0xffff,
+};
+
+/**
+ * @brief models SCOM restore header region.
+ */
+typedef struct
+{
+ uint16_t iv_magicMark;
+ uint8_t iv_version;
+ uint8_t iv_reserved1;
+ uint8_t iv_reserved2[4];
+ uint16_t iv_coreOffset;
+ uint16_t iv_coreLength;
+ uint16_t iv_eqOffset;
+ uint16_t iv_eqLength;
+ uint16_t iv_l2Offset;
+ uint16_t iv_l2Length;
+ uint16_t iv_l3Offset;
+ uint16_t iv_l3Length;
+} ScomRestoreHeader_t;
+
+/**
+ * @brief models a CPU register restoration area in STOP section of homer image.
+ */
+typedef struct
+{
+ uint8_t iv_threadRestoreArea[MAX_THREADS_PER_CORE][SMF_CORE_RESTORE_THREAD_AREA_SIZE];
+ uint8_t iv_threadSaveArea[MAX_THREADS_PER_CORE][SMF_SELF_SAVE_THREAD_AREA_SIZE];
+ uint8_t iv_coreRestoreArea[SMF_CORE_RESTORE_CORE_AREA_SIZE];
+ uint8_t iv_coreSaveArea[SMF_CORE_SAVE_CORE_AREA_SIZE];
+} SmfSprRestoreRegion_t;
+
+/**
+ * @brief models image section of CPMR in HOMER.
+ */
+typedef union CPMRSelfRestoreLayout
+{
+ uint8_t iv_region[SMF_SELF_RESTORE_CODE_SIZE];
+ struct
+ {
+ CpmrHeader_t iv_CPMRHeader;
+ uint8_t iv_exe[SMF_SELF_RESTORE_CODE_SIZE - sizeof(CpmrHeader_t)];
+ } elements;
+} CPMRSelfRestoreLayout_t;
+
+/**
+ * @brief models image section associated with core self restore in HOMER.
+ */
+typedef struct
+{
+ CPMRSelfRestoreLayout_t iv_CPMR_SR;
+ uint8_t iv_coreSelfRestore[SMF_SELF_RESTORE_CORE_REGS_SIZE];
+ uint8_t iv_reserve[SCOM_RESTORE_CPMR_OFFSET - SMF_SELF_RESTORE_SIZE_TOTAL];
+ uint8_t iv_coreScom[SCOM_RESTORE_SIZE_TOTAL];
+} SelfRestoreLayout_t;
+
+typedef struct
+{
+ SelfRestoreLayout_t iv_selfRestoreRegion;
+ uint8_t iv_qmeSramRegion[QME_REGION_SIZE];
+} CPMRLayout_t;
+
+/**
+ * @brief models image section associated with PGPE in HOMER.
+ */
+typedef struct
+{
+ uint8_t iv_ppmrHeader[PPMR_HEADER_SIZE];
+ uint8_t iv_bootCopier[PGPE_BOOT_COPIER_SIZE];
+ uint8_t iv_bootLoader[PGPE_BOOT_LOADER_SIZE];
+ uint8_t iv_pgpeSramRegion[OCC_SRAM_PGPE_REGION_SIZE];
+ uint8_t iv_reserve1[OCC_PSTATE_PARAM_BLOCK_PPMR_OFFSET - (PPMR_BOOT_REGION + OCC_SRAM_PGPE_REGION_SIZE)];
+ uint8_t iv_occPstateParamBlock[OCC_PSTATE_PARAM_BLOCK_REGION_SIZE];
+ uint8_t iv_pstateTable[PGPE_PSTATE_OUTPUT_TABLES_REGION_SIZE];
+ uint8_t iv_reserve2[PPMR_RESERVE_PSTATE_TABLE_TO_WOF];
+ uint8_t iv_wofTable[OCC_WOF_TABLES_SIZE];
+} PPMRLayout_t;
+
+/**
+ * @brief models XPMR in HOMER.
+ */
+typedef struct
+{
+ uint8_t iv_xpmrHeader[XPMR_HEADER_SIZE];
+ uint8_t iv_bootCopier[XGPE_BOOT_COPIER_LENGTH];
+ uint8_t iv_bootLoader[XGPE_BOOT_LOADER_LENGTH];
+ uint8_t iv_xgpeSramRegion[XGPE_SRAM_SIZE];
+} XPMRLayout_t;
+
+/**
+ * @brief models layout of HOMER.
+ */
+typedef struct
+{
+ uint8_t iv_occHostRegion[OCC_HOST_AREA_SIZE];
+ XPMRLayout_t iv_xpmrRegion;
+ uint8_t iv_xpmrReserve[ONE_MB - sizeof( XPMRLayout_t )];
+ CPMRLayout_t iv_cpmrRegion;
+ uint8_t iv_cpmrReserve[ONE_MB - sizeof( CPMRLayout_t )];
+ PPMRLayout_t iv_ppmrRegion;
+ uint8_t iv_ppmrReserve[ONE_MB - sizeof( PPMRLayout_t )];
+} Homerlayout_t;
+
+#ifdef __cplusplus
+#ifndef __PPE_PLAT
+}// namespace hcodeImageBuild ends
+#endif //__PPE_PLAT
+#endif //__cplusplus
+
+#endif //__ASSEMBLER__
+#endif //__HW_IMG_DEFINE
diff --git a/roms/skiboot/libpore/p10_stop_api.C b/roms/skiboot/libpore/p10_stop_api.C
new file mode 100644
index 000000000..4a8efa7cd
--- /dev/null
+++ b/roms/skiboot/libpore/p10_stop_api.C
@@ -0,0 +1,1816 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p10/procedures/utils/stopreg/p10_stop_api.C $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* EKB Project */
+/* */
+/* COPYRIGHT 2015,2019 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file p10_stop_api.C
+/// @brief implements STOP API which create/manipulate STOP image.
+///
+// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
+// *HWP Team : PM
+// *HWP Level : 2
+// *HWP Consumed by : HB:HYP
+
+// *INDENT-OFF*
+#ifdef PPC_HYP
+ #include <HvPlicModule.H>
+#endif
+
+#include "p10_stop_api.H"
+#include "p10_cpu_reg_restore_instruction.H"
+#include "p10_stop_data_struct.H"
+#include <string.h>
+#include "p10_stop_util.H"
+#include "p10_hcode_image_defines.H"
+#ifdef __cplusplus
+extern "C" {
+
+using namespace hcodeImageBuild;
+namespace stopImageSection
+{
+#endif
+// a true in the table below means register is of scope thread
+// whereas a false meanse register is of scope core.
+
+const StopSprReg_t g_sprRegister_p10[] =
+{
+ { PROC_STOP_SPR_CIABR, true, 0 },
+ { PROC_STOP_SPR_DAWR, true, 1 },
+ { PROC_STOP_SPR_DAWRX, true, 2 },
+ { PROC_STOP_SPR_HSPRG0, true, 3 },
+ { PROC_STOP_SPR_LDBAR, true, 4, },
+ { PROC_STOP_SPR_LPCR, true, 5 },
+ { PROC_STOP_SPR_PSSCR, true, 6 },
+ { PROC_STOP_SPR_MSR, true, 7 },
+ { PROC_STOP_SPR_HRMOR, false, 255 },
+ { PROC_STOP_SPR_HID, false, 21 },
+ { PROC_STOP_SPR_HMEER, false, 22 },
+ { PROC_STOP_SPR_PMCR, false, 23 },
+ { PROC_STOP_SPR_PTCR, false, 24 },
+ { PROC_STOP_SPR_SMFCTRL, true, 28 },
+ { PROC_STOP_SPR_USPRG0, true, 29 },
+ { PROC_STOP_SPR_USPRG1, true, 30 },
+ { PROC_STOP_SPR_URMOR, false, 255 },
+};
+
+const uint32_t MAX_SPR_SUPPORTED_P10 = 17;
+const uint32_t DEFAULT_CORE_SCOM_SUPPORTED = 15;
+const uint32_t DEFAULT_QUAD_SCOM_SUPPORTED = 255;
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief validated input arguments passed to proc_stop_save_cpureg_control.
+ * @param[in] i_pImage point to start of HOMER
+ * @param[in] i_coreId id of the core
+ * @param[in] i_threadId id of the thread
+ * @param[in] i_saveMaskVector SPR save bit mask vector
+ * @return STOP_SAVE_SUCCESS if function succeeds, error code otherwise.
+ */
+STATIC StopReturnCode_t validateArgumentSaveRegMask( void* const i_pImage,
+ uint32_t const i_coreId,
+ uint32_t const i_threadId,
+ uint64_t i_saveMaskVector )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+
+ do
+ {
+ if( !i_pImage )
+ {
+ l_rc = STOP_SAVE_ARG_INVALID_IMG;
+ break;
+ }
+
+ if( i_coreId > MAX_CORE_ID_SUPPORTED )
+ {
+ l_rc = STOP_SAVE_ARG_INVALID_CORE;
+ break;
+ }
+
+ if( i_threadId > MAX_THREAD_ID_SUPPORTED )
+ {
+ l_rc = STOP_SAVE_ARG_INVALID_THREAD;
+ break;
+ }
+
+ if( ( 0 == i_saveMaskVector ) || ( BAD_SAVE_MASK & i_saveMaskVector ) )
+ {
+ l_rc = STOP_SAVE_ARG_INVALID_REG;
+ break;
+ }
+
+ }
+ while(0);
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief validates input arguments provided by STOP API caller.
+ * @param[in] i_pImage pointer to beginning of chip's HOMER image.
+ * @param[in] i_regId SPR register id
+ * @param[in] i_coreId core id
+ * @param[in|out] i_pThreadId points to thread id
+ * @param[in|out] i_pThreadLevelReg points to scope information of SPR
+ * @return STOP_SAVE_SUCCESS if arguments found valid, error code otherwise.
+ * @note for register of scope core, function shall force io_threadId to
+ * zero.
+ */
+STATIC StopReturnCode_t validateSprImageInputs( void* const i_pImage,
+ const CpuReg_t i_regId,
+ const uint32_t i_coreId,
+ uint32_t* i_pThreadId,
+ bool* i_pThreadLevelReg )
+{
+ uint32_t index = 0;
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ bool sprSupported = false;
+ *i_pThreadLevelReg = false;
+
+ do
+ {
+ if( NULL == i_pImage )
+ {
+ // Error: HOMER image start location is not valid
+ // Cannot proceed further. So, let us exit.
+ l_rc = STOP_SAVE_ARG_INVALID_IMG;
+ MY_ERR( "invalid image location " );
+
+ break;
+ }
+
+ // STOP API manages STOP image based on physical core Id. PIR value
+ // is interpreted to calculate the physical core number and virtual
+ // thread number.
+ if( MAX_CORE_ID_SUPPORTED < i_coreId )
+ {
+ // Error: invalid core number. given core number exceeds maximum
+ // cores supported by chip.
+
+ // Physical core number is calculated based on following formula:
+ // core id = 4 * quad id (0..5) + core no within quad ( 0..3)
+ l_rc = STOP_SAVE_ARG_INVALID_CORE;
+ MY_ERR( "invalid core id " );
+ break;
+ }
+
+ if( MAX_THREAD_ID_SUPPORTED < *i_pThreadId )
+ {
+ //Error: invalid core thread. Given core thread exceeds maximum
+ //threads supported in a core.
+
+ // 64 bit PIR value is interpreted to calculate virtual thread
+ // Id. In fuse mode, b61 and b62 gives virtual thread id whereas in
+ // non fuse mode, b62 and b63 is read to determine the same.
+
+ l_rc = STOP_SAVE_ARG_INVALID_THREAD;
+ MY_ERR( "invalid thread " );
+ break;
+ }
+
+ for( index = 0; index < MAX_SPR_SUPPORTED_P10; ++index )
+ {
+ if( i_regId == (CpuReg_t )g_sprRegister_p10[index].iv_sprId )
+ {
+ // given register is in the list of register supported
+ sprSupported = true;
+ *i_pThreadLevelReg = g_sprRegister_p10[index].iv_isThreadScope;
+ *i_pThreadId = *i_pThreadLevelReg ? *i_pThreadId : 0;
+ break;
+ }
+ }
+
+ if( !sprSupported )
+ {
+ // Following SPRs are supported
+ // trace out all registers supported
+ MY_ERR("Register not supported" );
+ // error code to caller.
+ l_rc = STOP_SAVE_ARG_INVALID_REG;
+ break;
+ }
+
+ }
+ while(0);
+
+ if( l_rc )
+ {
+ MY_ERR( "regId %08d, coreId %d, "
+ "threadId %d return code 0x%08x", i_regId,
+ i_coreId, *i_pThreadId, l_rc );
+ }
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates ori instruction code.
+ * @param[in] i_Rs Source register number
+ * @param[in] i_Ra destination register number
+ * @param[in] i_data 16 bit immediate data
+ * @return returns 32 bit number representing ori instruction.
+ */
+STATIC uint32_t getOriInstruction( const uint16_t i_Rs, const uint16_t i_Ra,
+ const uint16_t i_data )
+{
+ uint32_t oriInstOpcode = 0;
+ oriInstOpcode = 0;
+ oriInstOpcode = ORI_OPCODE << 26;
+ oriInstOpcode |= i_Rs << 21;
+ oriInstOpcode |= i_Ra << 16;
+ oriInstOpcode |= i_data;
+
+ return SWIZZLE_4_BYTE(oriInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates 32 bit key used for SPR lookup in core section.
+ */
+STATIC uint32_t genKeyForSprLookup( const CpuReg_t i_regId )
+{
+ return getOriInstruction( 24, 0, (uint16_t) i_regId );
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates xor instruction code.
+ * @param[in] i_Rs source register number for xor operation
+ * @param[in] i_Ra destination register number for xor operation result
+ * @param[in] i_Rb source register number for xor operation
+ * @return returns 32 bit number representing xor immediate instruction.
+ */
+STATIC uint32_t getXorInstruction( const uint16_t i_Ra, const uint16_t i_Rs,
+ const uint16_t i_Rb )
+{
+ uint32_t xorRegInstOpcode;
+ xorRegInstOpcode = XOR_CONST << 1;
+ xorRegInstOpcode |= OPCODE_31 << 26;
+ xorRegInstOpcode |= i_Rs << 21;
+ xorRegInstOpcode |= i_Ra << 16;
+ xorRegInstOpcode |= i_Rb << 11;
+
+ return SWIZZLE_4_BYTE(xorRegInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates oris instruction code.
+ * @param[in] i_Rs source register number
+ * @param[in] i_Ra destination register number
+ * @param[in] i_data 16 bit immediate data
+ * @return returns 32 bit number representing oris immediate instruction.
+ */
+STATIC uint32_t getOrisInstruction( const uint16_t i_Rs, const uint16_t i_Ra,
+ const uint16_t i_data )
+{
+ uint32_t orisInstOpcode;
+ orisInstOpcode = 0;
+ orisInstOpcode = ORIS_OPCODE << 26;
+ orisInstOpcode |= ( i_Rs & 0x001F ) << 21 | ( i_Ra & 0x001F ) << 16;
+ orisInstOpcode |= i_data;
+
+ return SWIZZLE_4_BYTE(orisInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates instruction for mtspr
+ * @param[in] i_Rs source register number
+ * @param[in] i_Spr represents spr where data is to be moved.
+ * @return returns 32 bit number representing mtspr instruction.
+ */
+STATIC uint32_t getMtsprInstruction( const uint16_t i_Rs, const uint16_t i_Spr )
+{
+ uint32_t mtsprInstOpcode = 0;
+ uint32_t temp = (( i_Spr & 0x03FF ) << 11);
+ mtsprInstOpcode = (uint8_t)i_Rs << 21;
+ mtsprInstOpcode |= ( temp & 0x0000F800 ) << 5;
+ mtsprInstOpcode |= ( temp & 0x001F0000 ) >> 5;
+ mtsprInstOpcode |= MTSPR_BASE_OPCODE;
+
+ return SWIZZLE_4_BYTE(mtsprInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates instruction for mfmsr
+ * @param[in] i_Rt target register for SPR content.
+ * @return returns 32 bit number representing mfmsr instruction.
+ */
+STATIC uint32_t getMfmsrInstruction( const uint16_t i_Rt )
+{
+ uint32_t mfmsrInstOpcode = ((OPCODE_31 << 26) | (i_Rt << 21) | ((MFMSR_CONST)<< 1));
+
+ return SWIZZLE_4_BYTE(mfmsrInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates rldicr instruction.
+ * @param[in] i_Rs source register number
+ * @param[in] i_Ra destination register number
+ * @param[in] i_sh bit position by which contents of i_Rs are to be shifted
+ * @param[in] i_me bit position up to which mask should be 1.
+ * @return returns 32 bit number representing rldicr instruction.
+ */
+STATIC uint32_t getRldicrInstruction( const uint16_t i_Ra, const uint16_t i_Rs,
+ const uint16_t i_sh, uint16_t i_me )
+{
+ uint32_t rldicrInstOpcode = 0;
+ rldicrInstOpcode = ((RLDICR_OPCODE << 26 ) | ( i_Rs << 21 ) | ( i_Ra << 16 ));
+ rldicrInstOpcode |= ( ( i_sh & 0x001F ) << 11 ) | (RLDICR_CONST << 2 );
+ rldicrInstOpcode |= (( i_sh & 0x0020 ) >> 4);
+ rldicrInstOpcode |= (i_me & 0x001F ) << 6;
+ rldicrInstOpcode |= (i_me & 0x0020 );
+ return SWIZZLE_4_BYTE(rldicrInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+STATIC uint32_t getMfsprInstruction( const uint16_t i_Rt, const uint16_t i_sprNum )
+{
+ uint32_t mfsprInstOpcode = 0;
+ uint32_t temp = (( i_sprNum & 0x03FF ) << 11);
+ mfsprInstOpcode = (uint8_t)i_Rt << 21;
+ mfsprInstOpcode |= (( temp & 0x0000F800 ) << 5);
+ mfsprInstOpcode |= (( temp & 0x001F0000 ) >> 5);
+ mfsprInstOpcode |= MFSPR_BASE_OPCODE;
+
+ return SWIZZLE_4_BYTE(mfsprInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+STATIC uint32_t getBranchLinkRegInstruction(void)
+{
+ uint32_t branchConstInstOpcode = 0;
+ branchConstInstOpcode = (( OPCODE_18 << 26 ) | ( SELF_SAVE_FUNC_ADD ) | 0x03 );
+
+ return SWIZZLE_4_BYTE(branchConstInstOpcode);
+}
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief looks up entry for given SPR in given thread/core section.
+ * @param[in] i_pThreadSectLoc start of given thread section or core section.
+ * @param[in] i_lookUpKey search key for lookup of given SPR entry.
+ * @param[in] i_isThreadReg true if register is of scope thread, false
+ * otherwise.
+ * @param[in|out] io_pSprEntryLoc Input: NULL
+ * Output: location of given entry or end of table.
+ * @return STOP_SAVE_SUCCESS if entry is found, STOP_SAVE_FAIL in case of
+ * an error.
+ */
+STATIC StopReturnCode_t lookUpSprInImage( uint32_t* i_pThreadSectLoc, const uint32_t i_lookUpKey,
+ const bool i_isThreadReg, void** io_pSprEntryLoc )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_FAIL;
+ uint32_t temp = 0;
+ uint32_t* i_threadSectEnd = NULL;
+ uint32_t bctr_inst = SWIZZLE_4_BYTE(BLR_INST);
+ *io_pSprEntryLoc = NULL;
+
+ do
+ {
+ if( !i_pThreadSectLoc )
+ {
+ MY_ERR( "Bad SPR Start Location" );
+ break;
+ }
+
+ temp = i_isThreadReg ? (uint32_t)(SMF_CORE_RESTORE_THREAD_AREA_SIZE) :
+ (uint32_t)(SMF_CORE_RESTORE_CORE_AREA_SIZE);
+
+ i_threadSectEnd = i_pThreadSectLoc + ( temp >> 2 );
+
+ temp = 0;
+
+ while( ( i_pThreadSectLoc <= i_threadSectEnd ) &&
+ ( temp != bctr_inst ) )
+ {
+ temp = *i_pThreadSectLoc;
+
+ if( ( temp == i_lookUpKey ) || ( temp == bctr_inst ) )
+ {
+ *io_pSprEntryLoc = i_pThreadSectLoc;
+ l_rc = STOP_SAVE_SUCCESS;
+ break;
+ }
+
+ i_pThreadSectLoc = i_pThreadSectLoc + SIZE_PER_SPR_RESTORE_INST;
+ }
+ }
+ while(0);
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief updates an SPR STOP image entry.
+ * @param[in] i_pSprEntryLocation location of entry.
+ * @param[in] i_regId register Id associated with SPR.
+ * @param[in] i_regData data needs to be written to SPR entry.
+ * @return STOP_SAVE_SUCCESS if update works, STOP_SAVE_FAIL otherwise.
+ */
+STATIC StopReturnCode_t updateSprEntryInImage( uint32_t* i_pSprEntryLocation,
+ const CpuReg_t i_regId,
+ const uint64_t i_regData,
+ const enum SprEntryUpdateMode i_mode
+ )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ uint32_t tempInst = 0;
+ uint64_t tempRegData = 0;
+ bool newEntry = true;
+ uint16_t regRs = 0; //to use R0 for SPR restore insruction generation
+ uint16_t regRa = 0;
+
+ do
+ {
+ if( !i_pSprEntryLocation )
+ {
+ MY_ERR("invalid location of SPR image entry" );
+ l_rc = STOP_SAVE_FAIL;
+ break;
+ }
+
+ tempInst = genKeyForSprLookup( i_regId );
+
+ if( *i_pSprEntryLocation == tempInst )
+ {
+ newEntry = false;
+ }
+
+ //Add SPR search instruction i.e. "ori r0, r0, SPRID"
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ if( INIT_SPR_REGION == i_mode )
+ {
+ //adding inst 'b . + 0x1C'
+ *i_pSprEntryLocation = SWIZZLE_4_BYTE(SKIP_SPR_REST_INST);
+ }
+ else
+ {
+ //clear R0 i.e. "xor ra, rs, rb"
+ tempInst = getXorInstruction( regRs, regRs, regRs );
+ *i_pSprEntryLocation = tempInst;
+ }
+
+
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ tempRegData = i_regData >> 48;
+ //get lower order 16 bits of SPR restore value in R0
+ tempInst = getOrisInstruction( regRs, regRa, (uint16_t)tempRegData );
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ tempRegData = ((i_regData >> 32) & 0x0000FFFF );
+ //get bit b16-b31 of SPR restore value in R0
+ tempInst = getOriInstruction( regRs, regRa, (uint16_t)tempRegData );
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ //Rotate R0 to left by 32 bit position and zero lower order 32 bits.
+ //Place the result in R0
+ tempInst = getRldicrInstruction(regRa, regRs, 32, 31);
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ tempRegData = ((i_regData >> 16) & 0x000000FFFF );
+ //get bit b32-b47 of SPR restore value to R0
+ tempInst = getOrisInstruction( regRs, regRa, (uint16_t)tempRegData );
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ tempRegData = (uint16_t)i_regData;
+ //get bit b48-b63 of SPR restore value to R0
+ tempInst = getOriInstruction( regRs, regRa, (uint16_t)i_regData );
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ if( PROC_STOP_SPR_MSR == i_regId )
+ {
+ //MSR cannot be restored completely with mtmsrd instruction.
+ //as it does not update ME, LE and HV bits. In self restore code
+ //inorder to restore MSR, contents of R21 is moved to SRR1. It also
+ //executes an RFID which causes contents of SRR1 to be copied to
+ //MSR. This allows copy of LE bit which are specifically interested
+ //in. Instruction below moves contents of MSR Value (in R0 ) to R21.
+ tempInst = SWIZZLE_4_BYTE( MR_R0_TO_R21 );
+ }
+ else if ( PROC_STOP_SPR_HRMOR == i_regId )
+ {
+ //Case HRMOR, move contents of R0 to a placeholder GPR (R10)
+ //Thread Launcher expects HRMOR value in R10
+ tempInst = SWIZZLE_4_BYTE( MR_R0_TO_R10 );
+ }
+ else if( PROC_STOP_SPR_URMOR == i_regId )
+ {
+ //Case URMOR, move contents of R0 to a placeholder GPR (R9)
+ //Thread Launcher expects URMOR value in R9
+ tempInst = SWIZZLE_4_BYTE( MR_R0_TO_R9 );
+ }
+ else
+ {
+ // Case other SPRs, move contents of R0 to SPR
+ // For a UV system, even HRMOR is treated like any other SPR.
+ tempInst =
+ getMtsprInstruction( 0, (uint16_t)i_regId );
+ }
+
+ *i_pSprEntryLocation = tempInst;
+
+ if( newEntry )
+ {
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+ //at the end of SPR restore, add instruction BLR to go back to thread
+ //launcher.
+ tempInst = SWIZZLE_4_BYTE(BLR_INST);
+ *i_pSprEntryLocation = tempInst;
+ }
+ }
+ while(0);
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+STATIC StopReturnCode_t initSelfSaveEntry( void* const i_pImage, uint16_t i_sprNum )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ uint32_t* i_pSprSave = (uint32_t*)i_pImage;
+
+ //ori r0, r0, 0x00nn
+ *i_pSprSave = getOriInstruction( 0, 0, i_sprNum );
+
+ i_pSprSave++;
+
+ //addi r31, r31, 0x20
+ *i_pSprSave = SWIZZLE_4_BYTE(SKIP_SPR_SELF_SAVE);
+ i_pSprSave++;
+
+ //nop
+ *i_pSprSave = getOriInstruction( 0, 0, 0 );;
+ i_pSprSave++;
+
+ //mtlr, r30
+ *i_pSprSave = SWIZZLE_4_BYTE( MTLR_INST );
+ i_pSprSave++;
+
+ //blr
+ *i_pSprSave = SWIZZLE_4_BYTE(BLR_INST);
+ i_pSprSave++;
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+STATIC StopReturnCode_t getSprRegIndexAdjustment( const uint32_t i_saveMaskPos, uint32_t* i_sprAdjIndex )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+
+ do
+ {
+ if( (( i_saveMaskPos >= SPR_BIT_POS_8 ) && ( i_saveMaskPos <= SPR_BIT_POS_20 )) ||
+ (( i_saveMaskPos >= SPR_BIT_POS_25 ) && ( i_saveMaskPos <= SPR_BIT_POS_27 )) )
+ {
+ l_rc = STOP_SAVE_SPR_BIT_POS_RESERVE;
+ break;
+ }
+
+ if( (i_saveMaskPos > SPR_BIT_POS_20) && (i_saveMaskPos < SPR_BIT_POS_25) )
+ {
+ *i_sprAdjIndex = 12;
+ }
+ else if( i_saveMaskPos > SPR_BIT_POS_27 )
+ {
+ *i_sprAdjIndex = 15;
+ }
+ else
+ {
+ *i_sprAdjIndex = 0;
+ }
+
+ }
+ while(0);
+
+ return l_rc;
+}
+
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief returns core region and relative id wrt to quad
+ * @param[in] i_scomAddress scom address associated with a core
+ * @param[in] o_scomRegion SCOM region in HOMER
+ * @param[in] o_coreRelativeInst core relative id
+ * @return STOP_SAVE_SUCCESS if function succeeds, error code otherwise
+ */
+STATIC StopReturnCode_t decodeScomAddress( const uint32_t i_scomAddress, uint32_t * o_scomRegion,
+ uint32_t * o_coreRelativeInst )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ uint32_t l_regionSelect = ( i_scomAddress & CORE_REGION_MASK );
+ uint32_t l_endPoint = ( i_scomAddress & EP_SELECT_MASK );
+ l_endPoint = ( l_endPoint >> 16 );
+ l_regionSelect = l_regionSelect >> 12;
+
+ if( 1 == l_endPoint )
+ {
+ *o_scomRegion = PROC_STOP_SECTION_L3;
+ }
+ else if ( 2 == l_endPoint )
+ {
+ *o_scomRegion = PROC_STOP_SECTION_CORE;
+ }
+
+ switch( l_regionSelect )
+ {
+ case 8:
+ *o_coreRelativeInst = 0;
+ break;
+
+ case 4:
+ *o_coreRelativeInst = 1;
+ break;
+
+ case 2:
+ *o_coreRelativeInst = 2;
+ break;
+
+ case 1:
+ *o_coreRelativeInst = 3;
+ break;
+
+ default:
+ l_rc = STOP_SAVE_SCOM_INVALID_ADDRESS;
+ break;
+ }
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief validates all the input arguments.
+ * @param[in] i_pImage pointer to start of HOMER of image for proc chip.
+ * @param[in] i_scomAddress SCOM address of register.
+ * @param[in] i_chipletId core or cache chiplet id
+ * @param[in] i_operation operation requested for SCOM entry.
+ * @param[in] i_section image section on which operation is to be performed
+ * @return STOP_SAVE_SUCCESS if arguments found valid, error code otherwise.
+ * @note Function does not validate that the given SCOM address really
+ * belongs to the given section.
+ */
+STATIC StopReturnCode_t validateScomImageInputs( void* const i_pImage,
+ const uint32_t i_scomAddress,
+ const uint8_t i_chipletId,
+ const ScomOperation_t i_operation,
+ const ScomSection_t i_section )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ uint32_t l_scomRegion = 0;
+ uint32_t l_coreId = 0;
+
+ do
+ {
+ if( !i_pImage )
+ {
+ //Error Invalid image pointer
+ l_rc = STOP_SAVE_ARG_INVALID_IMG;
+ MY_ERR("invalid image location ");
+ break;
+ }
+
+ if( 0 == i_scomAddress )
+ {
+ l_rc = STOP_SAVE_SCOM_INVALID_ADDRESS;
+ MY_ERR("invalid SCOM address");
+ break;
+ }
+
+ if(( CACHE_CHIPLET_ID_MIN > i_chipletId ) ||
+ ( CACHE_CHIPLET_ID_MAX < i_chipletId ))
+ {
+ l_rc = STOP_SAVE_SCOM_INVALID_CHIPLET;
+ MY_ERR("chiplet id not valid");
+ break;
+ }
+
+ if(( PROC_STOP_SCOM_OP_MIN >= i_operation ) ||
+ ( PROC_STOP_SCOM_OP_MAX <= i_operation ))
+ {
+ //invalid SCOM image operation requested
+ l_rc = STOP_SAVE_SCOM_INVALID_OPERATION;
+ MY_ERR("invalid SCOM image operation");
+ break;
+ }
+
+ l_rc = decodeScomAddress( i_scomAddress, &l_scomRegion, &l_coreId );
+
+ if( l_rc )
+ {
+ MY_ERR( "Bad Scom Address 0x%08x", i_chipletId );
+ break;
+ }
+
+ if( PROC_STOP_SECTION_CORE == l_scomRegion )
+ {
+ if( ( i_section != PROC_STOP_SECTION_CORE ) ||
+ ( i_section != PROC_STOP_SECTION_L2 ) )
+ {
+ MY_ERR( "SCOM adress doesn't match with section type passed,"
+ " EP : %d , Section Type %d", l_scomRegion, i_section );
+ l_rc = STOP_SAVE_SCOM_INVALID_SECTION;
+ break;
+ }
+ }
+
+ if( PROC_STOP_SECTION_L3 == l_scomRegion )
+ {
+ if( ( i_section != PROC_STOP_SECTION_L3 ) ||
+ ( i_section != PROC_STOP_SECTION_CACHE ) )
+ {
+ MY_ERR( "SCOM adress doesn't match with section type passed,"
+ " EP : %d , Section Type %d", l_scomRegion, i_section );
+ l_rc = STOP_SAVE_SCOM_INVALID_SECTION;
+ break;
+ }
+ }
+ }
+ while(0);
+
+ if( l_rc )
+ {
+ MY_ERR("SCOMAddress 0x%08x chipletId 0x%08x operation"
+ "0x%08x section 0x%08x", i_scomAddress, i_chipletId,
+ i_operation, i_section );
+ }
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief determines HOMER region for SCOM restore entry request.
+ * @param[in] i_pImage points to base of HOMER image.
+ * @param[in] i_sectn SCOM restore section
+ * @param[in] i_instanceId core instance id
+ * @param[out]o_entryDat meta data pertaining to SCOM restore entry analysis
+ * @return STOP_SAVE_SUCCESS if HWP succeeds, error code otherwise.
+ */
+STATIC StopReturnCode_t lookUpScomRestoreRegion( void * i_pImage, const ScomSection_t i_sectn, uint32_t i_instanceId,
+ ScomEntryDat_t * o_entryDat )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ CpmrHeader_t * l_pCpmrHdr = NULL;
+ ScomRestoreHeader_t *l_scomHdr = NULL;
+ uint32_t l_relativeCorePos = 0;
+ uint32_t l_offset = 0;
+ uint32_t l_quadId = 0;
+ uint32_t l_scomLen = 0;
+
+ MY_INF( ">>lookUpScomRestoreRegion" );
+
+ o_entryDat->iv_subRegionBaseOffset = 0;
+ o_entryDat->iv_subRegionLength = 0;
+ l_quadId = ( i_instanceId >> 2 );
+
+ l_relativeCorePos = i_instanceId % MAX_CORES_PER_QUAD;
+ l_pCpmrHdr = ( CpmrHeader_t *) ( (uint8_t *) i_pImage + CPMR_HOMER_OFFSET );
+ l_scomLen = SWIZZLE_4_BYTE(l_pCpmrHdr->iv_maxCoreL2ScomEntry) +
+ SWIZZLE_4_BYTE(l_pCpmrHdr->iv_maxEqL3ScomEntry);
+ l_scomLen = ( l_scomLen * SCOM_RESTORE_ENTRY_SIZE );
+
+ l_offset = ( l_scomLen * l_quadId * MAX_CORES_PER_QUAD ) + SCOM_RESTORE_HOMER_OFFSET;
+
+ MY_INF( "QUAD_ID 0x%08x BASE OFFSET 0x%08x", l_quadId, l_offset );
+
+ l_scomHdr = ( ScomRestoreHeader_t *) ( (uint8_t *) i_pImage + l_offset );
+
+ if( ( PROC_STOP_SECTION_CORE == i_sectn ) || ( PROC_STOP_SECTION_L2 == i_sectn ) )
+ {
+ MY_INF( "Core Offset 0x%04x", SWIZZLE_2_BYTE(l_scomHdr->iv_coreOffset) );
+ l_offset += SWIZZLE_2_BYTE(l_scomHdr->iv_coreOffset);
+ o_entryDat->iv_subRegionLength = SWIZZLE_2_BYTE(l_scomHdr->iv_coreLength);
+ l_offset += ( SWIZZLE_4_BYTE(l_pCpmrHdr->iv_maxCoreL2ScomEntry) * l_relativeCorePos );
+ }
+ else if( ( PROC_STOP_SECTION_L3 == i_sectn ) || ( PROC_STOP_SECTION_CACHE == i_sectn ) )
+ {
+ MY_INF( "Cache Offset 0x%04x", SWIZZLE_2_BYTE(l_scomHdr->iv_l3Offset) );
+ l_offset += SWIZZLE_2_BYTE(l_scomHdr->iv_l3Offset);
+ o_entryDat->iv_subRegionLength = SWIZZLE_2_BYTE(l_scomHdr->iv_l3Length);
+ l_offset += ( SWIZZLE_4_BYTE(l_pCpmrHdr->iv_maxEqL3ScomEntry) * l_relativeCorePos );
+ }
+ else
+ {
+ o_entryDat->iv_subRegionBaseOffset = 0;
+ l_rc = STOP_SAVE_SCOM_INVALID_SECTION;
+ }
+
+ if( !l_rc )
+ {
+ o_entryDat->iv_subRegionBaseOffset = l_offset;
+ }
+
+ MY_INF( "SCOM Section Offset 0x%08x", l_offset );
+
+ MY_INF( "<<lookUpScomRestoreRegion" );
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief analyzes SCOM restore region and collects some data.
+ * @param[in] i_pImage points to base of HOMER image
+ * @param[in] i_sectn id associated with SCOM restore sub-region.
+ * @param[in] i_scomAddress fully qualified SCOM address
+ * @param[in] o_pScomDat meta data associated with entry analysis
+ * @return STOP_SAVE_SUCCESS if HWP succeeds, error code otherwise.
+ */
+STATIC StopReturnCode_t lookUpScomRestoreEntry( void * i_pImage, const ScomSection_t i_sectn,
+ uint32_t i_scomAddress, ScomEntryDat_t * o_pScomDat )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ ScomEntry_t * l_pScom = NULL;
+ CpmrHeader_t * l_pCpmrHdr = NULL;
+ uint8_t * l_pScomByte = NULL;
+ uint32_t l_entryLimit = 0;
+ uint8_t l_entry = 0;
+ uint32_t l_temp = 0;
+
+ MY_INF( ">> lookUpScomRestoreEntry" );
+
+ o_pScomDat->iv_slotFound = 0x00;
+ o_pScomDat->iv_entryOffset = 0x00;
+ o_pScomDat->iv_lastEntryOffset = 0x00;
+ o_pScomDat->iv_entryMatchOffset = 0x00;
+ o_pScomDat->iv_matchFound = 0x00;
+ l_pCpmrHdr = ( CpmrHeader_t * ) ( (uint8_t *) i_pImage + CPMR_HOMER_OFFSET );
+ l_pScomByte = ( uint8_t * )( (uint8_t *) i_pImage + o_pScomDat->iv_subRegionBaseOffset );
+ l_pScom = (ScomEntry_t *)( l_pScomByte );
+
+ switch( i_sectn )
+ {
+ case PROC_STOP_SECTION_CORE:
+ l_entryLimit = SWIZZLE_4_BYTE(l_pCpmrHdr->iv_maxCoreL2ScomEntry);
+ break;
+
+ case PROC_STOP_SECTION_L3:
+ l_entryLimit = SWIZZLE_4_BYTE(l_pCpmrHdr->iv_maxEqL3ScomEntry);
+ break;
+
+ default:
+ l_rc = STOP_SAVE_SCOM_INVALID_SECTION;
+ break;
+ }
+
+ if( l_rc )
+ {
+ return l_rc;
+ }
+
+ for( l_entry = 0; l_entry < l_entryLimit; l_entry++ )
+ {
+ if( !( l_pScom->iv_scomAddress & SWIZZLE_4_BYTE(SCOM_ENTRY_VALID) ) )
+ {
+ o_pScomDat->iv_slotFound = 0x01;
+ o_pScomDat->iv_entryOffset = l_entry;
+ break;
+ }
+
+ l_pScom++;
+ }
+
+ l_pScom = (ScomEntry_t *)( l_pScomByte );
+
+ for( l_entry = 0; l_entry < l_entryLimit; l_entry++ )
+ {
+ if( l_pScom->iv_scomAddress & SWIZZLE_4_BYTE(LAST_SCOM_ENTRY) )
+ {
+ o_pScomDat->iv_lastEntryOffset = l_entry;
+ MY_INF( "SCOM Restore Entry Limit 0x%08x",
+ o_pScomDat->iv_lastEntryOffset );
+ break;
+ }
+ l_pScom++;
+ }
+
+ l_pScom = (ScomEntry_t *)( l_pScomByte );
+
+ for( l_entry = 0; l_entry < l_entryLimit; l_entry++ )
+ {
+ l_temp = l_pScom->iv_scomAddress & SWIZZLE_4_BYTE(SCOM_ADDR_MASK);
+
+ if( SWIZZLE_4_BYTE((i_scomAddress & SCOM_ADDR_MASK)) == l_temp )
+ {
+ o_pScomDat->iv_entryMatchOffset = l_entry;
+ o_pScomDat->iv_matchFound = 0x01;
+ MY_INF( "Existing Entry Slot No 0x%08x", l_entry );
+ break;
+ }
+ l_pScom++;
+ }
+
+ o_pScomDat->iv_entryLimit = l_entryLimit;
+
+ MY_INF( "<< lookUpScomRestoreEntry" );
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+#define UNUSED(x) (void)(x)
+
+/**
+ * @brief edits a SCOM restore entry associated with the given core.
+ * @param[in] i_pScom points to SCOM restore location
+ * @param[in] i_scomAddr SCOM address of register.
+ * @param[in] i_scomData data associated with SCOM register.
+ * @param[in] i_operation operation to be performed on SCOM entry.
+ * @param[in] i_pScomDat points to meta data associated with entry analysis
+ * @return STOP_SAVE_SUCCESS if existing entry is updated, STOP_SAVE_FAIL
+ * otherwise.
+ */
+STATIC StopReturnCode_t editScomEntry( uint8_t * i_pScom, uint32_t i_scomAddr,
+ uint64_t i_scomData, ScomOperation_t i_operation,
+ ScomEntryDat_t * i_pScomDat )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ ScomEntry_t * l_pScom = (ScomEntry_t *)i_pScom;
+ UNUSED(i_scomAddr);
+
+ MY_INF( ">> editScomEntry " );
+
+ l_pScom = l_pScom + i_pScomDat->iv_entryMatchOffset;
+
+ switch( i_operation )
+ {
+ case PROC_STOP_SCOM_OR:
+ case PROC_STOP_SCOM_OR_APPEND:
+ l_pScom->iv_scomData |= SWIZZLE_8_BYTE(i_scomData);
+ break;
+
+ case PROC_STOP_SCOM_AND:
+ case PROC_STOP_SCOM_AND_APPEND:
+ l_pScom->iv_scomData &= SWIZZLE_8_BYTE(i_scomData);
+ break;
+
+ case PROC_STOP_SCOM_REPLACE:
+ l_pScom->iv_scomData = SWIZZLE_8_BYTE(i_scomData);
+ break;
+
+ default:
+ break;
+ }
+
+ MY_INF( "<< editScomEntry " );
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief update SCOM restore entry list associated with the given core.
+ * @param[in] i_pImage points to base of HOMER image.
+ * @param[in] i_scomAddr address of SCOM register.
+ * @param[in] i_scomData data associated with SCOM register.
+ * @param[in] i_sectn SCOM restore section in HOMER.
+ * @param[in] i_operation operation type requested on restore entry.
+ * @param[in] i_pScomDat points entry analysis meta data.
+ * @return STOP_SAVE_SUCCESS if new entry is added, STOP_SAVE_FAIL otherwise.
+ */
+STATIC StopReturnCode_t updateScomEntry( void * i_pImage, uint32_t i_scomAddr,
+ uint64_t i_scomData, const ScomSection_t i_sectn,
+ ScomOperation_t i_operation, ScomEntryDat_t * i_pScomDat )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ CpmrHeader_t * l_pCpmrHdr = NULL;
+ ScomEntry_t * l_pScom = NULL;
+ uint32_t l_maxScomEntry = 0;
+ l_pCpmrHdr = ( CpmrHeader_t * ) ( (uint8_t *) i_pImage + CPMR_HOMER_OFFSET );
+ l_pScom = ( ScomEntry_t * )( (uint8_t *) i_pImage + i_pScomDat->iv_subRegionBaseOffset );
+ switch( i_operation )
+ {
+ case PROC_STOP_SCOM_OR_APPEND:
+ case PROC_STOP_SCOM_AND_APPEND:
+ case PROC_STOP_SCOM_APPEND:
+ case PROC_STOP_SCOM_REPLACE:
+
+ l_pScom = l_pScom + i_pScomDat->iv_lastEntryOffset;
+
+ if( i_pScomDat->iv_entryLimit > i_pScomDat->iv_lastEntryOffset )
+ {
+ l_pScom->iv_scomAddress &= ~(SWIZZLE_LAST_SCOM_ENTRY);
+ l_pScom++; // takes us to offset stored in iv_entryOffset
+ l_pScom->iv_scomAddress = i_scomAddr & SCOM_ADDR_MASK;
+ l_pScom->iv_scomAddress |= (SCOM_ENTRY_VALID | LAST_SCOM_ENTRY | SCOM_ENTRY_VER);
+
+ if( PROC_STOP_SECTION_CORE == i_sectn )
+ {
+ l_maxScomEntry = SWIZZLE_4_BYTE(l_pCpmrHdr->iv_maxCoreL2ScomEntry);
+ l_pScom->iv_scomAddress |= CORE_SECTION_ID_CODE;
+ }
+ else
+ {
+ l_maxScomEntry = SWIZZLE_4_BYTE(l_pCpmrHdr->iv_maxEqL3ScomEntry);
+ l_pScom->iv_scomAddress |= L3_SECTION_ID_CODE;
+ }
+
+ l_pScom->iv_scomAddress |= ( l_maxScomEntry << MAX_SCOM_ENTRY_POS );
+ l_pScom->iv_scomAddress = SWIZZLE_4_BYTE(l_pScom->iv_scomAddress);
+ l_pScom->iv_scomData = SWIZZLE_8_BYTE(i_scomData);
+
+ MY_INF( "SCOM Data 0x%08x", SWIZZLE_4_BYTE(l_pScom->iv_scomAddress) );
+ }
+ else
+ {
+ MY_ERR( "Current Entry Count 0x%08x More than Max Entry Count 0x%08x",
+ i_pScomDat->iv_lastEntryOffset, i_pScomDat->iv_entryLimit );
+ l_rc = STOP_SAVE_MAX_ENTRY_REACHED;
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief searches a self save entry of an SPR in self-save segment.
+ * @param[in] i_sprBitPos bit position associated with SPR in save mask vector.
+ * @param[in] i_pSprSaveStart start location of SPR save segment
+ * @param[in] i_searchLength length of SPR save segment
+ * @param[in] i_pSaveSprLoc start location of save entry for a given SPR.
+ * @return STOP_SAVE_SUCCESS if look up succeeds, error code otherwise.
+ */
+STATIC StopReturnCode_t lookUpSelfSaveSpr( uint32_t i_sprBitPos, uint32_t* i_pSprSaveStart,
+ uint32_t i_searchLength, uint32_t** i_pSaveSprLoc )
+{
+ int32_t l_saveWordLength = (int32_t)(i_searchLength >> 2);
+ uint32_t l_oriInst = getOriInstruction( 0, 0, i_sprBitPos );
+ StopReturnCode_t l_rc = STOP_SAVE_FAIL;
+
+ while( l_saveWordLength > 0 )
+ {
+ if( l_oriInst == *i_pSprSaveStart )
+ {
+ *i_pSaveSprLoc = i_pSprSaveStart;
+ l_rc = STOP_SAVE_SUCCESS;
+ break;
+ }
+
+ i_pSprSaveStart++;
+ l_saveWordLength--;
+ }
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief searches a self save entry of an SPR in self-save segment.
+ * @param[in] i_pSaveReg start of editable location of a SPR save entry.
+ * @param[in] i_sprNum Id of the SPR for which entry needs to be edited.
+ * @return STOP_SAVE_SUCCESS if look up succeeds, error code otherwise.
+ */
+STATIC StopReturnCode_t updateSelfSaveEntry( uint32_t* i_pSaveReg, uint16_t i_sprNum )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+
+ do
+ {
+ if( !i_pSaveReg )
+ {
+ l_rc = STOP_SAVE_FAIL;
+ MY_ERR( "Failed to update self save area for SPR 0x%04x", i_sprNum );
+ break;
+ }
+
+ if( PROC_STOP_SPR_MSR == i_sprNum )
+ {
+ *i_pSaveReg = getMfmsrInstruction( 1 );
+ }
+ else
+ {
+ *i_pSaveReg = getMfsprInstruction( 1, i_sprNum );
+ }
+
+ i_pSaveReg++;
+
+ *i_pSaveReg = getBranchLinkRegInstruction( );
+ }
+ while(0);
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+StopReturnCode_t proc_stop_init_cpureg( void* const i_pImage, const uint32_t i_corePos )
+{
+
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ uint32_t* l_pRestoreStart = NULL;
+ void* l_pTempLoc = NULL;
+ Homerlayout_t* l_pHomer = NULL;
+ SmfSprRestoreRegion_t * l_pSprRest = NULL;
+ uint32_t l_threadPos = 0;
+ uint32_t l_lookUpKey = 0;
+ uint32_t l_sprIndex = 0;
+
+ MY_INF( ">> proc_stop_init_cpureg" );
+
+ do
+ {
+ if( !i_pImage )
+ {
+ l_rc = STOP_SAVE_ARG_INVALID_IMG;
+ break;
+ }
+
+ if( i_corePos > MAX_CORE_ID_SUPPORTED )
+ {
+ l_rc = STOP_SAVE_ARG_INVALID_CORE;
+ break;
+ }
+
+ l_pHomer = ( Homerlayout_t * ) i_pImage;
+
+ for( l_sprIndex = 0; l_sprIndex < MAX_SPR_SUPPORTED_P10; l_sprIndex++ )
+ {
+ //Check if a given SPR needs to be self-saved each time on STOP entry
+
+ l_lookUpKey = genKeyForSprLookup( ( CpuReg_t )g_sprRegister_p10[l_sprIndex].iv_sprId );
+ l_pSprRest =
+ ( SmfSprRestoreRegion_t * ) &l_pHomer->iv_cpmrRegion.iv_selfRestoreRegion.iv_coreSelfRestore[0];
+
+ l_pSprRest += i_corePos;
+
+ if( g_sprRegister_p10[l_sprIndex].iv_isThreadScope )
+ {
+ for( l_threadPos = 0; l_threadPos < MAX_THREADS_PER_CORE; l_threadPos++ )
+ {
+ l_pRestoreStart =
+ (uint32_t*)&l_pSprRest->iv_threadRestoreArea[l_threadPos][0];
+
+
+ l_rc = lookUpSprInImage( (uint32_t*)l_pRestoreStart, l_lookUpKey,
+ g_sprRegister_p10[l_sprIndex].iv_isThreadScope,
+ &l_pTempLoc );
+
+ if( l_rc )
+ {
+ MY_ERR( "Thread SPR lookup failed in proc_stop_init_cpureg SPR %d Core %d Thread %d Index %d",
+ g_sprRegister_p10[l_sprIndex].iv_sprId, i_corePos, l_threadPos, l_sprIndex );
+ break;
+ }
+
+ l_rc = updateSprEntryInImage( (uint32_t*) l_pTempLoc,
+ ( CpuReg_t )g_sprRegister_p10[l_sprIndex].iv_sprId,
+ 0x00,
+ INIT_SPR_REGION );
+
+ if( l_rc )
+ {
+ MY_ERR( "Thread SPR region init failed. Core %d SPR Id %d",
+ i_corePos, g_sprRegister_p10[l_sprIndex].iv_sprId );
+ break;
+ }
+
+ }//end for thread
+
+ if( l_rc )
+ {
+ break;
+ }
+
+ }//end if SPR threadscope
+ else
+ {
+ l_pRestoreStart = (uint32_t*)&l_pSprRest->iv_coreRestoreArea[0];
+
+ l_rc = lookUpSprInImage( (uint32_t*)l_pRestoreStart, l_lookUpKey,
+ g_sprRegister_p10[l_sprIndex].iv_isThreadScope, &l_pTempLoc );
+
+ if( l_rc )
+ {
+ MY_ERR( "Core SPR lookup failed in proc_stop_init_cpureg" );
+ break;
+ }
+
+ l_rc = updateSprEntryInImage( (uint32_t*) l_pTempLoc,
+ ( CpuReg_t )g_sprRegister_p10[l_sprIndex].iv_sprId,
+ 0x00,
+ INIT_SPR_REGION );
+
+ if( l_rc )
+ {
+ MY_ERR( "Core SPR region init failed. Core %d SPR Id %d SPR Index %d",
+ i_corePos, g_sprRegister_p10[l_sprIndex].iv_sprId, l_sprIndex );
+ break;
+ }
+
+ }// end else
+
+ }// end for l_sprIndex
+
+ }
+ while(0);
+
+ MY_INF( "<< proc_stop_init_cpureg" );
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------------------------------
+
+StopReturnCode_t proc_stop_save_scom( void* const i_pImage,
+ const uint32_t i_scomAddress,
+ const uint64_t i_scomData,
+ const ScomOperation_t i_operation,
+ const ScomSection_t i_section )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ uint32_t l_quadId = 0;
+ uint32_t l_coreId = 0;
+ uint32_t l_coreRegion = 0;
+ uint8_t * l_pScom = NULL;
+ ScomEntryDat_t l_entryDat;
+
+ MY_INF( ">> proc_stop_save_scom" );
+
+ do
+ {
+ l_quadId = i_scomAddress >> 24;
+ l_quadId = l_quadId & 0x3F;
+
+ l_rc = validateScomImageInputs( i_pImage, i_scomAddress,
+ l_quadId, i_operation, i_section );
+ if( l_rc )
+ {
+ MY_ERR( "invalid argument: aborting");
+ break;
+ }
+
+ l_rc = decodeScomAddress( i_scomAddress, &l_coreRegion, &l_coreId );
+
+ if( l_rc )
+ {
+ MY_ERR( "Failed To get Core Details For Address 0x%08x", i_scomAddress );
+ break;
+ }
+
+ //Converting Superchiplet Id to instance number
+ l_quadId = l_quadId - MIN_SUPERCHIPLET_ID;
+
+ //getting core position relative to the chip
+ l_coreId += ( l_quadId << 2 );
+
+ MY_INF( "Quad Id 0x%08x COre Id 0x%08x", l_quadId, l_coreId );
+
+ // Let us find the start address of SCOM area
+
+ l_rc = lookUpScomRestoreRegion( i_pImage,
+ i_section,
+ l_coreId,
+ &l_entryDat );
+ if( l_rc )
+ {
+ MY_ERR( "Failed To Find SCOM Section Requested 0x%08x",
+ ( uint32_t) i_section );
+ break;
+ }
+
+ l_pScom = (uint8_t *)( (uint8_t *)i_pImage + l_entryDat.iv_subRegionBaseOffset );
+
+ l_rc = lookUpScomRestoreEntry( i_pImage,
+ i_section,
+ i_scomAddress,
+ &l_entryDat );
+ if( l_rc )
+ {
+ MY_ERR( "Failed To Find SCOM Entry Slot 0x%08x", (uint32_t) l_rc );
+ break;
+ }
+
+ switch( i_operation )
+ {
+ case PROC_STOP_SCOM_APPEND:
+ l_rc = updateScomEntry( i_pImage,
+ i_scomAddress,
+ i_scomData,
+ i_section,
+ i_operation,
+ &l_entryDat );
+ break;
+
+ case PROC_STOP_SCOM_OR:
+ case PROC_STOP_SCOM_AND:
+ //case PROC_STOP_SCOM_NOOP:
+
+ if( l_entryDat.iv_matchFound )
+ {
+ l_rc = editScomEntry( l_pScom,
+ i_scomAddress,
+ i_scomData,
+ i_operation,
+ &l_entryDat );
+ }
+
+ break;
+
+ case PROC_STOP_SCOM_RESET:
+
+ l_rc = lookUpScomRestoreRegion( i_pImage,
+ PROC_STOP_SECTION_CORE,
+ l_coreId,
+ &l_entryDat );
+ if( l_rc )
+ {
+ MY_ERR( "Failed To Reset SCOM Section Requested 0x%08x",
+ ( uint32_t) i_section );
+ break;
+ }
+
+ memset( (uint8_t *)((uint8_t *)i_pImage + l_entryDat.iv_subRegionBaseOffset),
+ 0x00, l_entryDat.iv_subRegionLength );
+
+ l_rc = lookUpScomRestoreRegion( i_pImage,
+ PROC_STOP_SECTION_CACHE,
+ l_coreId,
+ &l_entryDat );
+ if( l_rc )
+ {
+ MY_ERR( "Failed To Reset SCOM Section Requested 0x%08x",
+ ( uint32_t) i_section );
+ break;
+ }
+
+ memset( (uint8_t *)((uint8_t *)i_pImage + l_entryDat.iv_subRegionBaseOffset),
+ 0x00, l_entryDat.iv_subRegionLength );
+
+ break;
+
+ case PROC_STOP_SCOM_OR_APPEND:
+ case PROC_STOP_SCOM_AND_APPEND:
+ case PROC_STOP_SCOM_REPLACE:
+
+ if( l_entryDat.iv_matchFound )
+ {
+ l_rc = editScomEntry( l_pScom,
+ i_scomAddress,
+ i_scomData,
+ i_operation,
+ &l_entryDat );
+ }
+ else
+ {
+ l_rc = updateScomEntry( i_pImage,
+ i_scomAddress,
+ i_scomData,
+ i_section,
+ i_operation,
+ &l_entryDat );
+ }
+
+ break;
+
+ default:
+ l_rc = STOP_SAVE_SCOM_INVALID_OPERATION;
+ break;
+ }
+ }
+ while(0);
+
+ if( l_rc )
+ {
+ MY_ERR("SCOM image operation 0x%08x failed for chiplet 0x%08x addr"
+ "0x%08x", i_operation, l_quadId ,
+ i_scomAddress );
+ }
+ else
+ {
+
+ }
+
+ MY_INF( "<< proc_stop_save_scom" );
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------------------------------
+
+StopReturnCode_t proc_stop_save_cpureg_control( void* i_pImage,
+ const uint64_t i_pir,
+ const uint32_t i_saveRegVector )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ uint32_t l_coreId = 0;
+ uint32_t l_threadId = 0;
+ uint32_t l_sprPos = 0;
+ uint32_t l_sprIndex = 0;
+ uint32_t l_lookupLength = 0;
+ uint32_t l_lookUpKey = 0;
+ uint32_t* l_pSaveStart = NULL;
+ uint32_t* l_pRestoreStart = NULL;
+ uint32_t* l_pSprSave = NULL;
+ void* l_pTempLoc = NULL;
+ uint32_t * l_pTempWord = NULL;
+ Homerlayout_t* l_pHomer = NULL;
+ SmfSprRestoreRegion_t * l_pSpr = NULL;
+ MY_INF(">> proc_stop_save_cpureg_control" );
+
+ do
+ {
+ l_rc = getCoreAndThread_p10( i_pImage, i_pir, &l_coreId, &l_threadId );
+
+ if( l_rc )
+ {
+ MY_ERR( "Error in getting core no 0x%08x and thread no 0x%08x from PIR 0x%016lx",
+ l_coreId, l_threadId, i_pir );
+ break;
+ }
+
+ l_rc = validateArgumentSaveRegMask( i_pImage, l_coreId, l_threadId, i_saveRegVector );
+
+ if( l_rc )
+ {
+ MY_ERR( "Invalid argument rc 0x%08x", (uint32_t) l_rc );
+ break;
+ }
+
+ l_pHomer = ( Homerlayout_t * )i_pImage;
+ l_pSpr = ( SmfSprRestoreRegion_t *) &l_pHomer->iv_cpmrRegion.iv_selfRestoreRegion.iv_coreSelfRestore[0];
+ l_pSpr += l_coreId;
+
+ for( l_sprIndex = 0; l_sprIndex < MAX_SPR_SUPPORTED_P10; l_sprIndex++ )
+ {
+ l_sprPos = g_sprRegister_p10[l_sprIndex].iv_saveMaskPos;
+
+ if( l_sprPos > MAX_SPR_BIT_POS )
+ {
+ continue;
+ }
+
+ //Check if a given SPR needs to be self-saved each time on STOP entry
+
+ if( i_saveRegVector & ( TEST_BIT_PATTERN >> l_sprPos ) )
+ {
+
+ if( g_sprRegister_p10[l_sprIndex].iv_isThreadScope )
+ {
+ l_lookupLength = SMF_SELF_SAVE_THREAD_AREA_SIZE;
+ l_pSaveStart =
+ (uint32_t*)&l_pSpr->iv_threadSaveArea[l_threadId][0];
+ l_pRestoreStart =
+ (uint32_t*)&l_pSpr->iv_threadRestoreArea[l_threadId][0];
+ }
+ else
+ {
+ l_lookupLength = SMF_CORE_SAVE_CORE_AREA_SIZE;
+ l_pSaveStart = (uint32_t*)&l_pSpr->iv_coreSaveArea[0];
+ l_pRestoreStart = (uint32_t*)&l_pSpr->iv_coreRestoreArea[0];
+ }
+
+ // an SPR restore section for given core already exists
+ l_lookUpKey = genKeyForSprLookup( ( CpuReg_t )g_sprRegister_p10[l_sprIndex].iv_sprId );
+
+ l_rc = lookUpSprInImage( (uint32_t*)l_pRestoreStart, l_lookUpKey,
+ g_sprRegister_p10[l_sprIndex].iv_isThreadScope, &l_pTempLoc );
+
+ if( l_rc )
+ {
+ //SPR specified in the save mask but there is no restore entry present in the memory
+ //Self-Save instruction will edit it during STOP entry to make it a valid entry
+
+ l_rc = proc_stop_save_cpureg( i_pImage,
+ (CpuReg_t)g_sprRegister_p10[l_sprIndex].iv_sprId,
+ 0x00, //creates a dummy entry
+ i_pir );
+ }
+
+ //Find if SPR-Save eye catcher exist in self-save segment of SPR restore region.
+ l_rc = lookUpSelfSaveSpr( l_sprPos, l_pSaveStart, l_lookupLength, &l_pSprSave );
+
+ if( l_rc )
+ {
+ MY_INF( "Failed to find SPR No %02d save entry", l_sprPos );
+ l_rc = STOP_SAVE_SPR_ENTRY_MISSING;
+ break;
+ }
+
+ l_pSprSave++; //point to next instruction location
+
+ //update specific instructions of self save region to enable saving for SPR
+ l_rc = updateSelfSaveEntry( l_pSprSave, g_sprRegister_p10[l_sprIndex].iv_sprId );
+
+ if( l_rc )
+ {
+ MY_ERR( "Failed to update self save instructions for 0x%08x",
+ (uint32_t) g_sprRegister_p10[l_sprIndex].iv_sprId );
+ }
+
+ if( l_pTempLoc )
+ {
+ l_pTempWord = (uint32_t *)l_pTempLoc;
+ l_pTempWord++;
+ *l_pTempWord = getXorInstruction( 0, 0, 0 );
+ }
+
+ }// end if( i_saveRegVector..)
+ }// end for
+ }
+ while(0);
+
+ MY_INF("<< proc_stop_save_cpureg_control" );
+
+ return l_rc;
+
+}
+
+//-----------------------------------------------------------------------------------------------------
+
+StopReturnCode_t proc_stop_save_cpureg( void* const i_pImage,
+ const CpuReg_t i_regId,
+ const uint64_t i_regData,
+ const uint64_t i_pir )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS; // procedure return code
+ SmfSprRestoreRegion_t* l_sprRegion = NULL;
+ Homerlayout_t* l_pHomer = NULL;
+
+ MY_INF(">> proc_stop_save_cpureg" );
+
+ do
+ {
+ uint32_t threadId = 0;
+ uint32_t coreId = 0;
+ uint32_t lookUpKey = 0;
+ void* pSprEntryLocation = NULL; // an offset w.r.t. to start of image
+ void* pThreadLocation = NULL;
+ bool threadScopeReg = false;
+
+ l_rc = getCoreAndThread_p10( i_pImage, i_pir, &coreId, &threadId );
+
+ if( l_rc )
+ {
+ MY_ERR("Failed to determine Core Id and Thread Id from PIR 0x%016lx",
+ i_pir);
+ break;
+ }
+
+ MY_INF( " PIR 0x%016lx coreId %d threadid %d "
+ " registerId %d", i_pir, coreId,
+ threadId, i_regId );
+
+ // First of all let us validate all input arguments.
+ l_rc = validateSprImageInputs( i_pImage,
+ i_regId,
+ coreId,
+ &threadId,
+ &threadScopeReg );
+ if( l_rc )
+ {
+ // Error: bad argument traces out error code
+ MY_ERR("Bad input argument rc %d", l_rc );
+
+ break;
+ }
+
+
+ l_pHomer = ( Homerlayout_t *) i_pImage;
+ l_sprRegion = ( SmfSprRestoreRegion_t* )&l_pHomer->iv_cpmrRegion.iv_selfRestoreRegion.iv_coreSelfRestore[0];
+ l_sprRegion += coreId;
+
+ if( threadScopeReg )
+ {
+ pThreadLocation = (uint32_t *)&l_sprRegion->iv_threadRestoreArea[threadId][0];
+ }
+ else
+ {
+ pThreadLocation = (uint32_t *)&l_sprRegion->iv_coreRestoreArea[0];
+ }
+
+ if( ( SWIZZLE_4_BYTE(BLR_INST) == *(uint32_t*)pThreadLocation ) ||
+ ( SWIZZLE_4_BYTE(ATTN_OPCODE) == *(uint32_t*) pThreadLocation ) )
+ {
+ // table for given core id doesn't exit. It needs to be
+ // defined.
+ pSprEntryLocation = pThreadLocation;
+ }
+ else
+ {
+ // an SPR restore section for given core already exists
+ lookUpKey = genKeyForSprLookup( i_regId );
+ l_rc = lookUpSprInImage( (uint32_t*)pThreadLocation,
+ lookUpKey,
+ threadScopeReg,
+ &pSprEntryLocation );
+ }
+
+ if( l_rc )
+ {
+ MY_ERR("Invalid or corrupt SPR entry. CoreId 0x%08x threadId "
+ "0x%08x regId 0x%08x lookUpKey 0x%08x "
+ , coreId, threadId, i_regId, lookUpKey );
+ break;
+ }
+
+ l_rc = updateSprEntryInImage( (uint32_t*) pSprEntryLocation,
+ i_regId,
+ i_regData,
+ UPDATE_SPR_ENTRY );
+
+ if( l_rc )
+ {
+ MY_ERR( " Failed to update the SPR entry of PIR 0x%016lx reg"
+ "0x%08x", (uint64_t)i_pir, i_regId );
+ break;
+ }
+
+ }
+ while(0);
+
+ MY_INF("<< proc_stop_save_cpureg" );
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------------------------------
+
+StopReturnCode_t proc_stop_init_self_save( void* const i_pImage, const uint32_t i_corePos )
+{
+
+ SmfSprRestoreRegion_t * l_pSelfSave = NULL;
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ uint32_t* l_pSaveStart = NULL;
+ Homerlayout_t * l_pHomer = NULL;
+ uint32_t l_threadPos = 0;
+ uint32_t l_sprBitPos = 0;
+ uint32_t l_sprIndexAdj = 0;
+
+ MY_INF(">> proc_stop_init_self_save" );
+
+ do
+ {
+ if( !i_pImage )
+ {
+ l_rc = STOP_SAVE_ARG_INVALID_IMG;
+ break;
+ }
+
+ if( i_corePos > MAX_CORE_ID_SUPPORTED )
+ {
+ l_rc = STOP_SAVE_ARG_INVALID_CORE;
+ break;
+ }
+
+ l_pHomer = ( Homerlayout_t* ) i_pImage;
+ l_pSelfSave =
+ ( SmfSprRestoreRegion_t *) &l_pHomer->iv_cpmrRegion.iv_selfRestoreRegion.iv_coreSelfRestore[0];
+
+ l_pSelfSave += i_corePos;
+
+ for( l_threadPos = 0; l_threadPos < MAX_THREADS_PER_CORE; l_threadPos++ )
+ {
+ l_pSaveStart =
+ (uint32_t*)&l_pSelfSave->iv_threadSaveArea[l_threadPos][0];
+
+ //Adding instruction 'mflr r30'
+ *l_pSaveStart = SWIZZLE_4_BYTE(MFLR_R30);
+ l_pSaveStart++;
+
+ for( l_sprBitPos = 0; l_sprBitPos <= MAX_SPR_BIT_POS; l_sprBitPos++ )
+ {
+ l_rc = getSprRegIndexAdjustment( l_sprBitPos, &l_sprIndexAdj );
+
+ if( STOP_SAVE_SPR_BIT_POS_RESERVE == l_rc )
+ {
+ //Failed to find SPR index adjustment
+ continue;
+ }
+
+ if( !g_sprRegister_p10[l_sprBitPos - l_sprIndexAdj].iv_isThreadScope )
+ {
+ continue;
+ }
+
+ //Initialize self save region with SPR save entry for each thread
+ //level SPR
+ l_rc = initSelfSaveEntry( l_pSaveStart,
+ g_sprRegister_p10[l_sprBitPos - l_sprIndexAdj].iv_saveMaskPos );
+
+ if( l_rc )
+ {
+ MY_ERR( "Failed to init thread self-save region for core %d thread %d",
+ i_corePos, l_threadPos );
+ break;
+ }
+
+ l_pSaveStart++;
+ l_pSaveStart++;
+ l_pSaveStart++;
+ }
+
+ }// for thread = 0;
+
+ if( l_rc )
+ {
+ //breakout if saw an error while init of thread SPR region
+ break;
+ }
+
+ l_pSaveStart =
+ (uint32_t*)&l_pSelfSave->iv_coreSaveArea[0];
+
+ *l_pSaveStart = SWIZZLE_4_BYTE(MFLR_R30);
+ l_pSaveStart++;
+
+ for( l_sprBitPos = 0; l_sprBitPos <= MAX_SPR_BIT_POS; l_sprBitPos++ )
+ {
+ l_rc = getSprRegIndexAdjustment( l_sprBitPos, &l_sprIndexAdj );
+
+ if( STOP_SAVE_SPR_BIT_POS_RESERVE == l_rc )
+ {
+ //Failed to find SPR index adjustment
+ continue;
+ }
+
+ if( g_sprRegister_p10[l_sprBitPos - l_sprIndexAdj].iv_isThreadScope )
+ {
+ continue;
+ }
+
+ //Initialize self save region with SPR save entry for each core
+ //level SPR
+ l_rc = initSelfSaveEntry( l_pSaveStart,
+ g_sprRegister_p10[l_sprBitPos - l_sprIndexAdj].iv_saveMaskPos );
+
+ if( l_rc )
+ {
+ MY_ERR( "Failed to init core self-save region for core %d thread %d",
+ i_corePos, l_threadPos );
+ break;
+ }
+
+ l_pSaveStart++;
+ l_pSaveStart++;
+ l_pSaveStart++;
+ }
+ }
+ while(0);
+
+ MY_INF("<< proc_stop_init_self_save" );
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------------------------------
+#ifdef __cplusplus
+} //namespace stopImageSection ends
+} //extern "C"
+#endif
diff --git a/roms/skiboot/libpore/p10_stop_api.H b/roms/skiboot/libpore/p10_stop_api.H
new file mode 100644
index 000000000..a70d2b281
--- /dev/null
+++ b/roms/skiboot/libpore/p10_stop_api.H
@@ -0,0 +1,238 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p10/procedures/utils/stopreg/p10_stop_api.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015,2021 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __P10_STOP_IMAGE_API_
+#define __P10_STOP_IMAGE_API_
+
+#include <stdint.h>
+
+#ifdef __SKIBOOT__
+ #include <skiboot.h>
+#endif
+
+///
+/// @file p10_stop_api.H
+/// @brief describes STOP API which create/manipulate STOP image.
+///
+// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
+// *HWP Team : PM
+// *HWP Level : 2
+// *HWP Consumed by : HB:HYP
+
+#ifdef __cplusplus
+namespace stopImageSection
+{
+#endif
+
+/**
+ * @brief all SPRs and MSR for which register restore is to be supported.
+ * @note STOP API design has built in support to accomodate 8 register of
+ * scope core and thread each.
+ */
+typedef enum
+{
+ PROC_STOP_SPR_DAWR = 180, // thread register
+ PROC_STOP_SPR_CIABR = 187, // thread register
+ PROC_STOP_SPR_DAWRX = 188, // thread register
+ PROC_STOP_SPR_HSPRG0 = 304, // thread register
+ PROC_STOP_SPR_HRMOR = 313, // core register
+ PROC_STOP_SPR_LPCR = 318, // thread register
+ PROC_STOP_SPR_HMEER = 337, // core register
+ PROC_STOP_SPR_PTCR = 464, // core register
+ PROC_STOP_SPR_USPRG0 = 496, // thread register
+ PROC_STOP_SPR_USPRG1 = 497, // thread register
+ PROC_STOP_SPR_URMOR = 505, // core register
+ PROC_STOP_SPR_SMFCTRL = 511, // thread register
+ PROC_STOP_SPR_LDBAR = 850, // thread register
+ PROC_STOP_SPR_PSSCR = 855, // thread register
+ PROC_STOP_SPR_PMCR = 884, // core register
+ PROC_STOP_SPR_HID = 1008, // core register
+ PROC_STOP_SPR_MSR = 2000, // thread register
+
+} CpuReg_t;
+
+/**
+ * @brief lists all the bad error codes.
+ */
+typedef enum
+{
+ STOP_SAVE_SUCCESS = 0,
+ STOP_SAVE_ARG_INVALID_IMG = 1,
+ STOP_SAVE_ARG_INVALID_REG = 2,
+ STOP_SAVE_ARG_INVALID_THREAD = 3,
+ STOP_SAVE_ARG_INVALID_MODE = 4,
+ STOP_SAVE_ARG_INVALID_CORE = 5,
+ STOP_SAVE_SPR_ENTRY_NOT_FOUND = 6,
+ STOP_SAVE_SPR_ENTRY_UPDATE_FAILED = 7,
+ STOP_SAVE_SCOM_INVALID_OPERATION = 8,
+ STOP_SAVE_SCOM_INVALID_SECTION = 9,
+ STOP_SAVE_SCOM_INVALID_ADDRESS = 10,
+ STOP_SAVE_SCOM_INVALID_CHIPLET = 11,
+ STOP_SAVE_SCOM_ENTRY_UPDATE_FAILED = 12,
+ STOP_SAVE_INVALID_FUSED_CORE_STATUS = 13,
+ STOP_SAVE_FAIL = 14, // for internal failure within firmware.
+ STOP_SAVE_SPR_ENTRY_MISSING = 15,
+ STOP_SAVE_MAX_ENTRY_REACHED = 16,
+ STOP_SAVE_SPR_BIT_POS_RESERVE = 17,
+} StopReturnCode_t;
+
+/**
+ * @brief summarizes all operations supported on scom entries of STOP image.
+ */
+typedef enum
+{
+ //enum members which are project agnostic
+ PROC_STOP_SCOM_OP_MIN = 0,
+ PROC_STOP_SCOM_APPEND = 1,
+ PROC_STOP_SCOM_REPLACE = 2,
+ PROC_STOP_SCOM_OR = 3,
+ PROC_STOP_SCOM_AND = 4,
+ PROC_STOP_SCOM_NOOP = 5,
+ PROC_STOP_SCOM_RESET = 6,
+ PROC_STOP_SCOM_OR_APPEND = 7,
+ PROC_STOP_SCOM_AND_APPEND = 8,
+ PROC_STOP_SCOM_OP_MAX = 9,
+
+} ScomOperation_t;
+
+/**
+ * @brief All subsections that contain scom entries in a STOP image.
+ */
+typedef enum
+{
+ PROC_STOP_SECTION_CORE = 1,
+ PROC_STOP_SECTION_L2 = 1,
+ PROC_STOP_SECTION_L3 = 2,
+ PROC_STOP_SECTION_CACHE = 2,
+} ScomSection_t;
+
+/**
+ * @brief versions pertaining relvant to STOP API.
+ */
+typedef enum
+{
+ STOP_API_VER = 0x00,
+ STOP_API_VER_CONTROL = 0x02,
+} VersionList_t;
+
+/**
+ * @brief Summarizes bit position allocated to SPRs in save bit mask vector.
+ */
+typedef enum
+{
+ BIT_POS_CIABR = 0,
+ BIT_POS_DAWR = 1,
+ BIT_POS_DAWRX = 2,
+ BIT_POS_HSPRG0 = 3,
+ BIT_POS_LDBAR = 4,
+ BIT_POS_LPCR = 5,
+ BIT_POS_PSSCR = 6,
+ BIT_POS_MSR = 7,
+ BIT_POS_HID = 21,
+ BIT_POS_HMEER = 22,
+ BIT_POS_PMCR = 23,
+ BIT_POS_PTCR = 24,
+ BIT_POS_SMFCTRL = 28,
+ BIT_POS_USPRG0 = 29,
+ BIT_POS_USPRG1 = 30,
+} SprBitPositionList_t;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**
+ * @brief creates SCOM restore entry for a given scom adress in HOMER.
+ * @param i_pImage points to start address of HOMER image.
+ * @param i_scomAddress address associated with SCOM restore entry.
+ * @param i_scomData data associated with SCOM restore entry.
+ * @param i_operation operation type requested for API.
+ * @param i_section section of HOMER in which restore entry needs to be created.
+ * @return STOP_SAVE_SUCCESS if API succeeds, error code otherwise.
+ * @note It is an API for creating SCOM restore entry in HOMER. It is agnostic to
+ * generation of POWER processor.
+ */
+
+StopReturnCode_t proc_stop_save_scom( void* const i_pImage,
+ const uint32_t i_scomAddress,
+ const uint64_t i_scomData,
+ const ScomOperation_t i_operation,
+ const ScomSection_t i_section );
+
+/**
+ * @brief initializes self save restore region of HOMER.
+ * @param[in] i_pImage points to base of HOMER image.
+ * @param[in] i_corePos position of the physical core.
+ * @return STOP_SAVE_SUCCESS if API succeeds, error code otherwise.
+ * @note It is an API for initializing self restore region in HOMER. It is agnostic to
+ * generation of POWER processor.
+ */
+StopReturnCode_t proc_stop_init_cpureg( void* const i_pImage, const uint32_t i_corePos );
+
+/**
+ * @brief enables self save for a given set of SPRs
+ * @param[in] i_pImage points to start address of HOMER image.
+ * @param[in] i_pir PIR value associated with core and thread.
+ * @param[in] i_saveRegVector bit vector representing the SPRs that needs to be self saved.
+ * @return STOP_SAVE_SUCCESS if API succeeds, error code otherwise.
+ * @note It is an API for enabling self save of SPRs and it is agnostic to
+ * generation of POWER processor.
+ */
+StopReturnCode_t proc_stop_save_cpureg_control( void* i_pImage,
+ const uint64_t i_pir,
+ const uint32_t i_saveRegVector );
+
+/**
+ * @brief creates an SPR restore entry in HOMER
+ * @param[in] i_pImage points to start address of HOMER image.
+ * @param[in] i_regId SPR number to be saved in HOMER
+ * @param[in] i_regData SPR data to be saved in HOMER
+ * @param[in] i_pir PIR value associated with core and thread.
+ * @return STOP_SAVE_SUCCESS if API succeeds, error code otherwise.
+ * @note It is an API for enabling self save of SPRs and it is agnostic to
+ * generation of POWER processor.
+ */
+StopReturnCode_t proc_stop_save_cpureg( void* const i_pImage,
+ const CpuReg_t i_regId,
+ const uint64_t i_regData,
+ const uint64_t i_pir );
+
+/**
+ * @brief initializes self-save region with specific instruction.
+ * @param[in] i_pImage points to start address of HOMER image.
+ * @param[in] i_corePos physical core's relative position within processor chip.
+ * @return STOP_SAVE_SUCCESS if self-save is initialized successfully,
+ * error code otherwise.
+ * @note API is project agnostic and is intended only for use case of HOMER build.
+ * There is no explicit effort to support any other use case.
+ */
+StopReturnCode_t proc_stop_init_self_save( void* const i_pImage, const uint32_t i_corePos );
+
+#ifdef __cplusplus
+} // extern "C"
+}; // namespace stopImageSection ends
+#endif //__cplusplus
+
+#endif //__P10_STOP_IMAGE_API_
diff --git a/roms/skiboot/libpore/p10_stop_data_struct.H b/roms/skiboot/libpore/p10_stop_data_struct.H
new file mode 100644
index 000000000..3a16fcda9
--- /dev/null
+++ b/roms/skiboot/libpore/p10_stop_data_struct.H
@@ -0,0 +1,162 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p10/procedures/utils/stopreg/p10_stop_data_struct.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* EKB Project */
+/* */
+/* COPYRIGHT 2015,2020 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file p10_stop_data_struct.H
+/// @brief describes data structures internal to STOP API.
+///
+// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
+// *HWP Team : PM
+// *HWP Level : 2
+// *HWP Consumed by : HB:HYP
+#ifndef __STOP_DATA_STRUCT_
+#define __STOP_DATA_STRUCT_
+
+#include "p10_hcd_memmap_base.H"
+
+#ifdef __SKIBOOT__
+ #include <skiboot.h>
+#endif
+
+#ifdef __FAPI_2_
+ #include <fapi2.H>
+#endif
+
+#ifdef PPC_HYP
+
+ #define STATIC
+
+#else
+
+ #define STATIC static
+
+#endif
+
+
+#ifdef __DEBUG_
+ #include<stdio.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+namespace stopImageSection
+{
+#endif
+
+/**
+ * @brief Misc constants pertaining to instruction opcodes.
+ */
+enum
+{
+ MAX_SPR_RESTORE_INST = 0x08,
+ SIZE_PER_SPR_RESTORE_INST = ((4 * sizeof(uint8_t)) / sizeof(uint32_t)),
+ MAX_THREAD_LEVEL_SPRS = 11,
+ MAX_CORE_LEVEL_SPRS = 6,
+ MAX_SPR_BIT_POS = 30,
+ SPR_BIT_POS_8 = 8,
+ SPR_BIT_POS_20 = 20,
+ SPR_BIT_POS_25 = 25,
+ SPR_BIT_POS_27 = 27,
+};
+
+/**
+ * @brief various operations supported on SPR restore entry.
+ */
+enum SprEntryUpdateMode
+{
+ INIT_SPR_REGION = 0x01,
+ UPDATE_SPR_ENTRY = 0x02,
+};
+
+/**
+ * @brief models an individual SCOM restore entry.
+ */
+typedef struct
+{
+ uint32_t iv_scomAddress;
+ uint64_t iv_scomData;
+} __attribute__((packed)) ScomEntry_t;
+
+/**
+ * @brief describes details pertaining to SCOM entry
+ */
+typedef struct
+{
+ uint32_t iv_subRegionBaseOffset;
+ uint32_t iv_subRegionLength;
+ uint8_t iv_slotFound;
+ uint8_t iv_lastEntryOffset;
+ uint16_t iv_entryOffset;
+ uint8_t iv_entryMatchOffset;
+ uint8_t iv_matchFound;
+ uint8_t iv_entryLimit;
+ uint8_t iv_reserved;
+} ScomEntryDat_t;
+
+/**
+ * @brief summarizes attributes associated with a SPR register.
+ */
+typedef struct
+{
+ uint32_t iv_sprId;
+ bool iv_isThreadScope;
+ uint32_t iv_saveMaskPos;
+} StopSprReg_t;
+
+/**
+ * @brief Misc constants.
+ */
+enum
+{
+ SIZE_SCOM_ENTRY = sizeof( ScomEntry_t ),
+ SCOM_ENTRY_START = 0xDEADDEAD,
+ BAD_SAVE_MASK = 0x007FF000,
+ MAX_SPR_INDEX = 31,
+ TEST_BIT_PATTERN = 0x80000000,
+ EP_SELECT_MASK = 0x000F0000,
+ CORE_REGION_MASK = 0x0000F000,
+ SCOM_ENTRY_VALID = 0x80000000,
+ LAST_SCOM_ENTRY = 0x40000000,
+ SWIZZLE_LAST_SCOM_ENTRY = 0x00000040,
+ SCOM_ADDR_MASK = 0x0000FFFF,
+ SCOM_ADDR_CHIPLET_MASK = 0x000FFFFF,
+ SCOM_ENTRY_VER = 0x10000000, //Ver 1.0
+ CORE_SECTION_ID_CODE = 0x00000000, //Core Section Id 0
+ L3_SECTION_ID_CODE = 0x03000000, //L3 Section Id 3 b4:b7
+ MAX_SCOM_ENTRY_POS = 0x10,
+ MIN_SUPERCHIPLET_ID = 0x20,
+
+};
+
+#ifdef __DEBUG_
+ #define MY_ERR( _fmt_, _args_...) printf( "\n"); printf( _fmt_, ##_args_)
+ #define MY_INF(_fmt_, _args_...) printf( "\n"); printf( _fmt_, ##_args_)
+#else
+ #define MY_ERR( _fmt_, _args_...)
+ #define MY_INF(_fmt_, _args_...)
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+
+} //namespace stopImageSection ends
+#endif //__cplusplus
+
+#endif
diff --git a/roms/skiboot/libpore/p10_stop_util.C b/roms/skiboot/libpore/p10_stop_util.C
new file mode 100644
index 000000000..ba3ec1535
--- /dev/null
+++ b/roms/skiboot/libpore/p10_stop_util.C
@@ -0,0 +1,190 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: chips/p10/procedures/utils/stopreg/p10_stop_util.C $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* EKB Project */
+/* */
+/* COPYRIGHT 2019 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file p10_stop_util.C
+/// @brief implements some utilty functions for STOP API.
+///
+// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
+// *HWP Team : PM
+// *HWP Level : 2
+// *HWP Consumed by : HB:HYP
+#ifdef PPC_HYP
+ #include <HvPlicModule.H>
+#endif
+
+#include "p10_stop_api.H"
+#include "p10_stop_util.H"
+#include "p10_stop_data_struct.H"
+#include "p10_hcd_memmap_base.H"
+#include "p10_hcode_image_defines.H"
+#include "stddef.h"
+
+#ifdef __cplusplus
+using namespace hcodeImageBuild;
+namespace stopImageSection
+{
+#endif
+
+//-----------------------------------------------------------------------
+
+/**
+ * @brief Returns proc chip's fuse mode status.
+ * @param i_pImage points to start of chip's HOMER image.
+ * @param o_fusedMode points to fuse mode information.
+ * @return STOP_SAVE_SUCCESS if functions succeeds, error code otherwise.
+ */
+STATIC StopReturnCode_t isFusedMode( void* const i_pImage, bool* o_fusedMode )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ uint64_t l_cpmrCheckWord = 0;
+ uint32_t* l_pMagic = NULL;
+ CpmrHeader_t* l_pCpmr = NULL;
+ *o_fusedMode = false;
+
+ do
+ {
+
+ if( !i_pImage )
+ {
+ MY_ERR( "invalid pointer to HOMER image");
+ l_rc = STOP_SAVE_ARG_INVALID_IMG;
+ break;
+ }
+
+ l_pMagic = (uint32_t*)( (uint8_t*)i_pImage + CPMR_HOMER_OFFSET + 8 );
+ l_cpmrCheckWord = SWIZZLE_4_BYTE( *l_pMagic );
+
+ if( CPMR_REGION_CHECK_WORD != l_cpmrCheckWord )
+ {
+ MY_ERR("corrupt or invalid HOMER image location 0x%016lx",
+ l_cpmrCheckWord );
+ l_rc = STOP_SAVE_ARG_INVALID_IMG;
+ break;
+ }
+
+ l_pCpmr = (CpmrHeader_t*)( (uint8_t*)i_pImage + CPMR_HOMER_OFFSET );
+
+ if( (uint8_t) FUSED_CORE_MODE == l_pCpmr->iv_fusedMode )
+ {
+ *o_fusedMode = true;
+ break;
+ }
+
+ if( (uint8_t) NONFUSED_CORE_MODE == l_pCpmr->iv_fusedMode )
+ {
+ break;
+ }
+
+ MY_ERR("Unexpected value 0x%08x for fused mode. Bad or corrupt "
+ "HOMER location", l_pCpmr->iv_fusedMode );
+ l_rc = STOP_SAVE_INVALID_FUSED_CORE_STATUS ;
+
+ }
+ while(0);
+
+ return l_rc;
+}
+
+//----------------------------------------------------------------------
+
+StopReturnCode_t getCoreAndThread_p10( void* const i_pImage, const uint64_t i_pir,
+ uint32_t* o_pCoreId, uint32_t* o_pThreadId )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+
+ do
+ {
+ // for SPR restore using 'Virtual Thread' and 'Physical Core' number
+ // In Fused Mode:
+ // bit b28 and b31 of PIR give physical core and b29 and b30 gives
+ // virtual thread id.
+ // In Non Fused Mode
+ // bit 28 and b29 of PIR give both logical and physical core number
+ // whereas b30 and b31 gives logical and virtual thread id.
+ bool fusedMode = false;
+ uint8_t coreThreadInfo = (uint8_t)i_pir;
+ *o_pCoreId = 0;
+ *o_pThreadId = 0;
+ l_rc = isFusedMode( i_pImage, &fusedMode );
+
+ if( l_rc )
+ {
+ MY_ERR(" Checking Fused mode. Read failed 0x%08x", l_rc );
+ break;
+ }
+
+ if( fusedMode )
+ {
+ if( coreThreadInfo & FUSED_CORE_BIT1 )
+ {
+ *o_pThreadId = 2;
+ }
+
+ if( coreThreadInfo & FUSED_CORE_BIT2 )
+ {
+ *o_pThreadId += 1;
+ }
+
+ if( coreThreadInfo & FUSED_CORE_BIT0 )
+ {
+ *o_pCoreId = 2;
+ }
+
+ if( coreThreadInfo & FUSED_CORE_BIT3 )
+ {
+ *o_pCoreId += 1;
+ }
+ }
+ else
+ {
+ if( coreThreadInfo & FUSED_CORE_BIT0 )
+ {
+ *o_pCoreId = 2;
+ }
+
+ if ( coreThreadInfo & FUSED_CORE_BIT1 )
+ {
+ *o_pCoreId += 1;
+ }
+
+ if( coreThreadInfo & FUSED_CORE_BIT2 )
+ {
+ *o_pThreadId = 2;
+ }
+
+ if( coreThreadInfo & FUSED_CORE_BIT3 )
+ {
+ *o_pThreadId += 1;
+ }
+ }
+
+ MY_INF("Core Type %s", fusedMode ? "Fused" : "Un-Fused" );
+ //quad field is not affected by fuse mode
+ *o_pCoreId += 4 * (( coreThreadInfo & 0x70 ) >> 4 );
+ }
+ while(0);
+
+ return l_rc;
+}
+
+#ifdef __cplusplus
+}//namespace stopImageSection ends
+#endif
diff --git a/roms/skiboot/libpore/p10_stop_util.H b/roms/skiboot/libpore/p10_stop_util.H
new file mode 100644
index 000000000..7836dbc86
--- /dev/null
+++ b/roms/skiboot/libpore/p10_stop_util.H
@@ -0,0 +1,123 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p10/procedures/hwp/lib/p10_stop_util.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016,2019 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __P10_STOP_UTIL_
+#define __P10_STOP_UTIL_
+
+#include <stdint.h>
+
+#ifdef _AIX
+ #define __BYTE_ORDER __BIG_ENDIAN
+#elif __SKIBOOT__
+ #include <skiboot.h>
+#else
+ #include <endian.h>
+#endif
+
+#ifndef __PPE_PLAT
+ #include "p10_stop_api.H"
+#endif
+
+#ifdef FAPI_2
+ #include <fapi2.H>
+#endif
+
+///
+/// @file p10_stop_util.H
+/// @brief describes some utilty functions for STOP API.
+///
+// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
+// *HWP Team : PM
+// *HWP Level : 2
+// *HWP Consumed by : HB:HYP
+#ifndef __PPE_PLAT
+#ifdef __cplusplus
+namespace stopImageSection
+{
+#endif
+#endif //__PPE_PLAT
+/**
+ * @brief helper function to swizzle given input data
+ * @note swizles bytes to handle endianess issue.
+ */
+#if( __BYTE_ORDER == __BIG_ENDIAN )
+
+// NOP if it is a big endian system
+#define SWIZZLE_2_BYTE(WORD) WORD
+#define SWIZZLE_4_BYTE(WORD) WORD
+#define SWIZZLE_8_BYTE(WORD) WORD
+
+#else
+#define SWIZZLE_2_BYTE(WORD) \
+ ( (((WORD) >> 8) & 0x00FF) | (((WORD) << 8) & 0xFF00) )
+
+#define SWIZZLE_4_BYTE(WORD) \
+ ( { uint64_t l_tmp64 = WORD; \
+ (uint32_t)( (((l_tmp64) >> 24) & 0x000000FF) | (((l_tmp64) >> 8) & 0x0000FF00) | \
+ (((l_tmp64) << 8) & 0x00FF0000) | (((l_tmp64) << 24) & 0xFF000000) ) ;\
+ })
+
+#define SWIZZLE_8_BYTE(WORD) \
+ ( (((WORD) >> 56) & 0x00000000000000FF) | \
+ (((WORD) >> 40) & 0x000000000000FF00)| \
+ (((WORD) >> 24) & 0x0000000000FF0000) | \
+ (((WORD) >> 8) & 0x00000000FF000000) | \
+ (((WORD) << 8) & 0x000000FF00000000) | \
+ (((WORD) << 24) & 0x0000FF0000000000) | \
+ (((WORD) << 40) & 0x00FF000000000000) | \
+ (((WORD) << 56) & 0xFF00000000000000) )
+#endif
+
+/**
+ * @brief enumerates bit(s) positions of interest for PIR.
+ */
+enum
+{
+ FUSED_CORE_BIT0 = 0x08,
+ FUSED_CORE_BIT1 = 0x04,
+ FUSED_CORE_BIT2 = 0x02,
+ FUSED_CORE_BIT3 = 0x01,
+ QUAD_BITS = 0x70,
+};
+
+#ifndef __PPE_PLAT
+/**
+ * @brief returns core id and thread id by parsing a given PIR.
+ * @param i_pStopImage points to STOP image associated with a proc chip.
+ * @param i_pir PIR associated with a core's thread.
+ * @param o_coreId points to core id value obtained from PIR.
+ * @param o_threadId points to thread id value obtained from PIR.
+ * @return SUCCESS if function suceeds, error code otherwise.
+ */
+StopReturnCode_t getCoreAndThread_p10( void* const i_pStopImage,
+ const uint64_t i_pir,
+ uint32_t* o_coreId,
+ uint32_t* o_threadId );
+#ifdef __cplusplus
+} // namespace stopImageSection ends
+
+#endif
+#endif //__PPE_PLAT
+#endif
diff --git a/roms/skiboot/libpore/p8_delta_scan_rw.h b/roms/skiboot/libpore/p8_delta_scan_rw.h
new file mode 100644
index 000000000..54002e408
--- /dev/null
+++ b/roms/skiboot/libpore/p8_delta_scan_rw.h
@@ -0,0 +1,468 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/hwpf/hwp/build_winkle_images/p8_slw_build/p8_delta_scan_rw.h $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012,2014 */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: p8_delta_scan_rw.h,v 1.49 2014/05/13 13:31:51 jmcgill Exp $
+#define OVERRIDE_OFFSET 8 // Byte offset of forward pointer's addr relative
+ // to base forward pointer's addr.
+#define SIZE_IMAGE_BUF_MAX 5000000 // Max ~5MB image buffer size.
+#define SIZE_IMAGE_CENTAUR_MAX 5000000 // Max ~5MB image buffer size.
+#define SIZE_REPR_RING_MAX 50000 // Max ~50kB repr ring buffer size.
+#define SCOM_REG_MASK 0x00ffffff // Scom register mask (within a chiplet)
+#define CID_MASK 0xff000000 // Chiplet ID mask
+#define CID_EX_LOW 0x10 // Lowest EX chiplet addr
+#define CID_EX_HIGH 0x1f // Highest EX chiplet addr
+
+/***** Xip customize support ****/
+#define COMBINED_GOOD_VECTORS_TOC_NAME "combined_good_vectors"
+#define L2_SINGLE_MEMBER_ENABLE_TOC_NAME "l2_single_member_enable_mask"
+#define PROC_PIB_REPR_VECTOR_TOC_NAME "proc_sbe_pibmem_repair_vector"
+#define NEST_SKEWADJUST_VECTOR_TOC_NAME "proc_sbe_nest_skewadjust_vector"
+#define SECURITY_SETUP_VECTOR_TOC_NAME "proc_sbe_security_setup_vector"
+#define VALID_BOOT_CORES_MASK_TOC_NAME "valid_boot_cores_mask"
+#define MAX_PLL_RING_SIZE 128 // Bytes
+#define PERV_BNDY_PLL_RING_TOC_NAME "perv_bndy_pll_ring"
+#define PERV_BNDY_PLL_RING_ALT_TOC_NAME "perv_bndy_pll_ring_alt"
+#define MAX_FUNC_L3_RING_LIST_ENTRIES 64
+#define MAX_FUNC_L3_RING_SIZE 7000 // Bytes
+#define FUNC_L3_RING_TOC_NAME "ex_func_l3_ring"
+#define MAX_CEN_PLL_RING_SIZE 80 // Bytes
+#define TP_PLL_BNDY_RING_ALT_TOC_NAME "tp_pll_bndy_ring_alt"
+#define STANDALONE_MBOX0_VALUE_TOC_NAME "standalone_mbox0_value"
+#define STANDALONE_MBOX1_VALUE_TOC_NAME "standalone_mbox1_value"
+#define STANDALONE_MBOX2_VALUE_TOC_NAME "standalone_mbox2_value"
+#define STANDALONE_MBOX3_VALUE_TOC_NAME "standalone_mbox3_value"
+#define UNTRUSTED_BAR_TOC_NAME "fabric_config"
+#define UNTRUSTED_PBA_BAR_TOC_NAME "fabric_config_pba"
+#define REFCLOCK_TERM_TOC_NAME "refclock_term"
+
+/***** Scan setting *****/
+#define OPCG_SCAN_RATIO 4
+#define P8_OPCG_SCAN_RATIO_BITS (uint64_t(OPCG_SCAN_RATIO-1)<<(63-8))
+#define P8_OPCG_GO_BITS (uint64_t(0x40000000)<<32)
+#define P8_SCAN_POLL_MASK_BIT15 (uint64_t(0x00010000)<<32)
+
+/***** Scan Control Regs *****/
+#define P8_PORE_OPCG_CTRL_REG0_0x00030002 0x00030002 // OPCG control reg 0
+#define P8_PORE_OPCG_CTRL_REG1_0x00030003 0x00030003 // OPCG control reg 1
+#define P8_PORE_OPCG_CTRL_REG2_0x00030004 0x00030004 // OPCG control reg 2
+#define P8_PORE_OPCG_START_REG3_0x00030005 0x00030005 // OPCG start reg 3
+#define P8_PORE_CLOCK_REGION_0x00030006 0x00030006 // Clock region control
+#define P8_PORE_CLOCK_CONTROLLER_REG 0x00030007 // Addr of clock ctrl scom reg
+#define P8_PORE_CLOCK_STATUS_0x00030008 0x00030008 // Status of clocks running
+#define P8_PORE_SHIFT_REG 0x00038000 // Addr of scom reg that does scan ring shifting
+#define P8_SCAN_CHECK_WORD 0xA5A55A5A // Header check word
+
+/***** Ring state *****/
+#define MAX_RING_SIZE 500000 // 500kbits is the max ring size in bits
+
+/***** Return codes *****/
+#define DSLWB_RING_SEARCH_MATCH 0
+#define DSLWB_RING_SEARCH_EXHAUST_MATCH 30
+#define DSLWB_RING_SEARCH_NO_MATCH 31
+#define DSLWB_RING_SEARCH_MESS 32
+#define DSLWB_SLWB_SUCCESS 0
+#define DSLWB_SLWB_NO_RING_MATCH 40
+#define DSLWB_SLWB_DX_ERROR 41
+#define DSLWB_SLWB_WF_ERROR 42
+#define DSLWB_SLWB_WF_IMAGE_ERROR 43
+#define DSLWB_SLWB_IMAGE_ERROR 44
+#define DSLWB_SLWB_UNKNOWN_ERROR 45
+#define IMGBUILD_SUCCESS 0 // Successful img build.
+#define IMGBUILD_ERR_GENERIC 1 // Non-specific error code.
+#define IMGBUILD_ERR_FILE_ACCESS 2 // Unable to access/open file.
+#define IMGBUILD_ERR_CHIPLET_ID_MESS 4 // Chiplet ID mess(mostly for VPD rings).
+#define IMGBUILD_NO_RINGS_FOUND 5 // Successful img build but no rings found.
+#define IMGBUILD_BAD_ARGS 6 // Bad function arguments.
+#define IMGBUILD_ERR_MEMORY 7 // Memory allocation error.
+#define IMGBUILD_ERR_RING_TOO_LARGE 8 // Ring size exceeds HB/PHYP's buffer.
+#define IMGBUILD_ERR_CHECK_CODE 9 // Coding or image data problem.
+#define IMGBUILD_INVALID_IMAGE 10 // Invalid image.
+#define IMGBUILD_IMAGE_SIZE_MISMATCH 11 // Mismatch between image sizes.
+#define IMGBUILD_IMAGE_SIZE_MESS 12 // Messed up image or section sizes.
+#define IMGBUILD_RINGTYPE_NOT_ALLOWED 13 // Ringtype not allowed.
+#define IMGBUILD_BUFFER_TOO_SMALL 14 // Buffer too small.
+#define IMGBUILD_ERR_PORE_INLINE 20 // Pore inline error.
+#define IMGBUILD_ERR_PORE_INLINE_ASM 21 // Err assoc w/inline assembler.
+#define IMGBUILD_RING_SEARCH_MATCH 0
+#define IMGBUILD_RING_SEARCH_EXHAUST_MATCH 30
+#define IMGBUILD_RING_SEARCH_NO_MATCH 31
+#define IMGBUILD_RING_SEARCH_MESS 32
+#define IMGBUILD_ERR_RING_SEARCH 33 // Err assoc w/ring retrieval.
+#define IMGBUILD_ERR_DATACARE_RING_MESS 34 // Err assoc w/datacare & vpd ring sizes.
+#define IMGBUILD_ERR_WF_CREATE 45 // Err assoc w/create_wiggle_flip_prg.
+#define IMGBUILD_ERR_RING_WRITE_TO_IMAGE 46 // Err assoc w/wr_ring_block_to_img.
+#define IMGBUILD_ERR_SECTION_SIZING 48 // Err assoc w/section sizing.
+#define IMGBUILD_ERR_GET_SECTION 49 // Err assoc w/getting section ID.
+#define IMGBUILD_ERR_SECTION_DELETE 50 // Err assoc w/deleting ELF section.
+#define IMGBUILD_ERR_APPEND 51 // Err assoc w/appending to ELF section.
+#define IMGBUILD_ERR_INCOMPLETE_IMG_BUILD 52 // The image was built, but with errors.
+#define IMGBUILD_ERR_FWD_BACK_PTR_MESS 53 // Forward or backward pointer mess.
+#define IMGBUILD_ERR_KEYWORD_NOT_FOUND 54 // Image keyword not found.
+#define IMGBUILD_ERR_MISALIGNED_RING_LAYOUT 55 // Ring layout is misaligned.
+#define IMGBUILD_ERR_IMAGE_TOO_LARGE 56 // Image too large. Exceeded max size.
+#define IMGBUILD_ERR_XIP_MISC 57 // Miscellaneous XIP image error.
+#define IMGBUILD_ERR_XIP_UNKNOWN 58 // Unknown XIP image error.
+#define IMGBUILD_ERR_RS4_DECOMPRESS 59 // Error during RS4 decompression.
+#define IMGBUILD_ERR_RS4_COMPRESS 60 // Error during RS4 compression.
+#define IMGBUILD_ERR_RAM_HDRS_NOT_SYNCED 61 // Ram headers not synchronized.
+#define IMGBUILD_ERR_RAM_TABLE_FULL 63 // Ram table is full.
+#define IMGBUILD_ERR_RAM_CODE 64 // Code error in Ram API code.
+#define IMGBUILD_ERR_RAM_INVALID_PARM 65 // Invalid Ramming parameter.
+#define IMGBUILD_WARN_RAM_TABLE_CONTAMINATION 66 // Ram table contamination
+#define IMGBUILD_ERR_RAM_TABLE_FAIL 67 // Unsuccessful RAM table build.
+#define IMGBUILD_ERR_RAM_TABLE_END_NOT_FOUND 68 // Table entry end bit not found.
+#define IMGBUILD_ERR_SCOM_INVALID_PARM 70 // Invalid Scomming parameter.
+#define IMGBUILD_ERR_SCOM_HDRS_NOT_SYNCD 72 // Scom headers out of sync.
+#define IMGBUILD_ERR_SCOM_ENTRY_NOT_FOUND 74 // Scom entry not found (OR/AND oper.)
+#define IMGBUILD_ERR_SCOM_REPEAT_ENTRIES 76 // Repeat entries not allow.
+#define IMGBUILD_ERR_SCOM_INVALID_SUBSECTION 77 // Invalid subsection value.
+#define IMGBUILD_ERR_SCOM_TABLE_FAIL 79 // Unsuccessful SCOM table build.
+
+#if defined SLW_COMMAND_LINE_RAM || defined XIPC_COMMAND_LINE
+#define SLW_COMMAND_LINE
+#endif
+
+#if defined __FAPI && !(defined __P8_PORE_TABLE_GEN_API_C)
+#define MY_INF(_fmt_, _args_...) FAPI_INF(_fmt_, ##_args_)
+#ifndef SLW_COMMAND_LINE
+#define MY_ERR(_fmt_, _args_...) FAPI_ERR(_fmt_, ##_args_)
+#else
+#define MY_ERR(_fmt_, _args_...) FAPI_INF(_fmt_, ##_args_)
+#endif // End of SLW_COMMAND_LINE
+#define MY_DBG(_fmt_, _args_...) FAPI_DBG(_fmt_, ##_args_)
+#else // End of __FAPI
+#ifdef SLW_COMMAND_LINE
+#define MY_INF(_fmt_, _args_...) printf(_fmt_, ##_args_)
+#define MY_ERR(_fmt_, _args_...) printf(_fmt_, ##_args_)
+#define MY_DBG(_fmt_, _args_...) printf(_fmt_, ##_args_)
+#else // End of SLW_COMMAND_LINE
+#ifdef __SKIBOOT__
+#define pr_fmt(fmt) "LIBPORE: " fmt
+#include <skiboot.h>
+//#define MY_INF(_fmt_, _args_...) prlog(PR_TRACE, _fmt_, ##_args_)
+#define MY_INF(_fmt_, _args_...) do { } while(0)
+#define MY_ERR(_fmt_, _args_...) prerror(_fmt_, ##_args_)
+//#define MY_DBG(_fmt_, _args_...) prlog(PR_INSANE, _fmt_, ##_args_)
+#define MY_DBG(_fmt_, _args_...) do { } while(0)
+#else
+#define MY_INF(_fmt_, _args_...) do { } while(0)
+#define MY_ERR(_fmt_, _args_...) do { } while(0)
+#define MY_DBG(_fmt_, _args_...) do { } while(0)
+#endif
+#endif // End of not(__FAPI) & not(SLW_COMMAND_LINE)
+#endif
+
+#ifdef SLW_COMMAND_LINE
+// Debug and development stuff
+//#define IGNORE_FOR_NOW // Causes code sections to be ignored.
+#define DEBUG_SUPPORT // Activates sbe-xip debug support.
+#endif
+
+/* XXX TEMPORARY */
+#ifdef __SKIBOOT__
+#define DEBUG_SUPPORT // Activates sbe-xip debug support.
+#endif
+
+//#include <stdio.h>
+//#include <stdint.h>
+//#include <stdlib.h>
+#include <p8_pore_api_custom.h>
+#include <string.h>
+
+#if defined SLW_COMMAND_LINE
+#include <stdint.h> // May be in conflict with p8_pore_api_custom.h
+#include <stdlib.h> // May be in conflict with p8_pore_api_custom.h
+#include <stdio.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#endif //End of SLW_COMMAND_LINE
+
+// Not needed by:
+// - Done: p8_pore_table_gen_api, p8_slw_build, p8_xip_customize, sbe_xip_tool,
+// p8_delta_scan, p8_ipl_build, p8_centaur_build.
+// - So, what was this used for?
+//#include <pore_bitmanip.H>
+
+#include <p8_image_help_base.H>
+
+#if !(defined __P8_PORE_TABLE_GEN_API_C) && !(defined __CEN_XIP_CUSTOMIZE_C) && !(defined SLW_COMMAND_LINE_RAM)
+// We don't need this include for gen_cpureg/scom or slw ramming.
+#include <p8_scan_compression.H>
+#endif
+
+#undef __PORE_INLINE_ASSEMBLER_C__
+#include <pore_inline.h>
+
+#if( defined(__cplusplus) && !defined(PLIC_MODULE) )
+extern "C" {
+#endif
+
+
+#if !(defined __P8_PORE_TABLE_GEN_API_C) && !(defined SLW_COMMAND_LINE_RAM)
+
+// Info:
+// DeltaRingLayout describes the sequential order of the content in the compressed delta
+// ring blocks in the .initf section in the SBE-XIP images.
+// When creating the .initf delta ring blocks, the following rules must be followed:
+// - Everything must be stored in BE format.
+// - {entryOffset; sizeOfThis; sizeOfMeta; metaData} must be word-aligned to ensure
+// that the {rs4Launch} starts on a word boundary.
+// - {rs4Launch} must start on a word boundary (see earlier rule how to do that).
+// - {entryOffset; sizeOfThis; sizeOfMeta; metaData; rs4Launch} must be double-word-
+// aligned to ensure that {rs4Delta} starts on a double-word boundary.
+// - {rs4Delta} must start on a double-word bournday (see earlier rule how to do that).
+//
+typedef struct {
+ uint64_t entryOffset;
+ uint64_t backItemPtr;
+ uint32_t sizeOfThis;
+ uint32_t sizeOfMeta; // Exact size of meta data. Arbitrary size. Not null terminated.
+ uint32_t ddLevel;
+ uint8_t sysPhase;
+ uint8_t override;
+ uint8_t reserved1;
+ uint8_t reserved2;
+ char *metaData; // Arbitrary size. Extra bytes to next alignment are random or 0s.
+ uint32_t *rs4Launch; // Code. Must be 4-byte aligned. Actually should be 8-B align!
+ uint32_t *rs4Delta; // Data. Must be 8-byte aligned.
+ uint32_t *wfInline; // Code. Must be 4-byte aligned. Actually should be 8-B align!
+} DeltaRingLayout;
+
+typedef struct {
+ uint32_t sizeOfData;
+ char data[];
+} MetaData;
+
+int calc_ring_delta_state(
+ const uint32_t *i_init,
+ const uint32_t *i_alter,
+ uint32_t *o_delta,
+ const uint32_t i_ringLen);
+
+int create_wiggle_flip_prg(
+ uint32_t *i_deltaRing,
+ uint32_t i_ringBitLen,
+ uint32_t i_scanSelectData,
+ uint32_t i_chipletID,
+ uint32_t **o_wfInline,
+ uint32_t *o_wfInlineLenInWords,
+ uint8_t i_flushOptimization,
+ uint32_t i_scanMaxRotate,
+ uint32_t i_waitsScanDelay,
+ uint32_t i_ddLevel);
+
+uint64_t calc_ring_layout_entry_offset(
+ uint8_t i_typeRingLayout,
+ uint32_t i_sizeMetaData);
+
+int write_ring_block_to_image(
+ void *io_image,
+ const char *i_ringName, // NULL if no name.
+ DeltaRingLayout *i_ringBlock,
+ const uint8_t i_idxVector, // [0-15] - Ignored if ringName==NULL
+ const uint8_t i_override, // [0,1] - Ignored if ringName==NULL
+ const uint8_t i_overridable, // [0,1] - Ignored if ringName==NULL
+ const uint32_t i_sizeImageMax,
+ const uint8_t i_xipSectionId,
+ void *i_bufTmp,
+ const uint32_t i_sizeBufTmp);
+
+#if !(defined __CEN_XIP_CUSTOMIZE_C)
+
+int p8_centaur_build(
+ void *i_imageIn,
+ uint32_t i_ddLevel,
+ void *i_imageOut,
+ uint32_t i_sizeImageOutMax);
+
+int p8_ipl_build(
+ void *i_imageIn,
+ uint32_t i_ddLevel,
+ void *i_imageOut,
+ uint32_t i_sizeImageOutMax);
+
+int get_ring_layout_from_image2(
+ const void *i_imageIn,
+ uint32_t i_ddLevel,
+ uint8_t i_sysPhase,
+ DeltaRingLayout **o_rs4RingLayout,
+ void **nextRing,
+ uint8_t i_xipSectionId);
+
+int gen_ring_delta_state(
+ uint32_t bitLen,
+ uint32_t *i_init,
+ uint32_t *i_alter,
+ uint32_t *o_delta,
+ uint32_t verbose);
+
+int write_rs4_ring_to_ref_image(
+ char *i_fnImage,
+ CompressedScanData *i_RS4,
+ uint32_t i_ddLevel,
+ uint8_t i_sysPhase,
+ uint8_t i_override,
+ uint8_t i_ringType,
+ char *i_varName,
+ char *i_fnMetaData,
+ void *i_bufTmp,
+ uint32_t i_sizeBufTmp,
+ uint32_t verbose);
+
+int write_vpd_ring_to_ipl_image(
+ void *io_image,
+ uint32_t &io_sizeImageOut,
+ CompressedScanData *i_bufRs4Ring,
+ uint32_t i_ddLevel,
+ uint8_t i_sysPhase,
+ char *i_ringName,
+ void *i_bufTmp,
+ uint32_t i_sizeBufTmp,
+ uint8_t i_xipSection);
+
+int write_vpd_ring_to_slw_image(
+ void *io_image,
+ uint32_t &io_sizeImageOut,
+ CompressedScanData *i_bufRs4Ring,
+ uint32_t i_ddLevel,
+ uint8_t i_sysPhase,
+ char *i_ringName,
+ void *i_bufTmp,
+ uint32_t i_sizeBufTmp,
+ uint8_t i_bWcSpace);
+
+int check_and_perform_ring_datacare(
+ void *i_imageRef,
+ void *io_buf1,
+ uint8_t i_ddLevel,
+ uint8_t i_sysPhase,
+ char *i_ringName,
+ void *i_buf2,
+ uint32_t i_sizeBuf2);
+
+int get_delta_ring_from_image(
+ char *i_fnImage,
+ char *i_varName,
+ uint32_t i_ddLevel,
+ uint8_t i_sysPhase,
+ uint8_t i_override,
+ MetaData **o_metaData,
+ CompressedScanData **o_deltaRingRS4,
+ uint32_t verbose);
+
+int write_wiggle_flip_to_image(
+ void *io_imageOut,
+ uint32_t *i_sizeImageMaxNew,
+ DeltaRingLayout *i_ringLayout,
+ uint32_t *i_wfInline,
+ uint32_t i_wfInlineLenInWords);
+
+int get_ring_layout_from_image(
+ const void *i_imageIn,
+ uint32_t i_ddLevel,
+ uint8_t i_sysPhase,
+ DeltaRingLayout *o_rs4RingLayout,
+ void **nextRing);
+
+int append_empty_section(
+ void *io_image,
+ int *i_sizeImageMaxNew,
+ uint32_t i_sectionId,
+ int *i_sizeSection,
+ uint8_t i_bFixed);
+
+int initialize_slw_section(
+ void *io_image,
+ uint32_t *i_sizeImageMaxNew);
+
+int create_and_initialize_fixed_image(
+ void *io_image);
+
+int update_runtime_scom_pointer(
+ void *io_image);
+
+void cleanup(
+ void *buf1=NULL,
+ void *buf2=NULL,
+ void *buf3=NULL,
+ void *buf4=NULL,
+ void *buf5=NULL);
+
+#endif // End of !(defined __CEN_XIP_CUSTOMIZE_C)
+
+#endif // End of !(defined __P8_PORE_TABLE_GEN_API_C) && !(defined SLW_COMMAND_LINE_RAM)
+
+// Byte-reverse a 32-bit integer if on an LE machine
+static 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
+static 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;
+}
+
+// N-byte align an address, offset or size (aos)
+static inline uint64_t myByteAlign( const uint8_t nBytes, const uint64_t aos)
+{
+ return ((aos+nBytes-1)/nBytes)*nBytes;
+}
+
+#if( defined(__cplusplus) && !defined(PLIC_MODULE) )
+}
+#endif
diff --git a/roms/skiboot/libpore/p8_image_help_base.H b/roms/skiboot/libpore/p8_image_help_base.H
new file mode 100644
index 000000000..4662641ec
--- /dev/null
+++ b/roms/skiboot/libpore/p8_image_help_base.H
@@ -0,0 +1,125 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/hwpf/hwp/build_winkle_images/p8_slw_build/p8_image_help_base.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012,2014 */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: p8_image_help_base.H,v 1.18 2013/06/10 22:08:20 jeshua Exp $
+//------------------------------------------------------------------------------
+// Title: p8_image_help_base.H
+// Description: Contains the most basic structures and defines needed for
+// image building and interpretation.
+//------------------------------------------------------------------------------
+#ifndef _P8_IMAGE_HELP_BASE_H_
+#define _P8_IMAGE_HELP_BASE_H_
+
+#include <sbe_xip_image.h>
+
+//
+// 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.
+// Fixed SLW image size (Ensure 128-byte alignment.)
+const uint32_t FIXED_SLW_IMAGE_SIZE = 1024*1024; // Fixed SLW image size for _fixed.
+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 PORE 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/roms/skiboot/libpore/p8_pore_api_custom.h b/roms/skiboot/libpore/p8_pore_api_custom.h
new file mode 100644
index 000000000..473030a71
--- /dev/null
+++ b/roms/skiboot/libpore/p8_pore_api_custom.h
@@ -0,0 +1,141 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/hwpf/hwp/build_winkle_images/p8_slw_build/p8_pore_api_custom.h $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012,2014 */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+/* $Id: p8_pore_api_custom.h,v 1.5 2012/05/22 21:25:21 cmolsen Exp $ */
+/* $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/utils/p8_pore_api_custom.h,v $ */
+
+#include <stdint.h> /* for uint32_t */
+#include <stdio.h> /* for printf */
+#if !defined(__HOSTBOOT_MODULE) && !defined(__SKIBOOT__)
+#include <netinet/in.h> /* for htonl */
+#endif
+
+/**
+ * This file should be modified by users to appropriately handle some
+ * environment-specific operations.
+ */
+
+
+/*********************************/
+/***** Logging and Tracing *****/
+/*********************************/
+/**
+ * All tracing functions assume printf-style formatting
+ */
+
+#ifndef __FAPI
+/* Trace an informational message */
+#define P8_PORE_ITRACE0(msg) printf("PORE> INFO: " msg "\n");
+#define P8_PORE_ITRACE1(msg, arg0) printf("PORE> INFO: " msg "\n", arg0);
+
+/* Trace an error message */
+#define P8_PORE_ETRACE0(msg) printf("PORE> ERROR: " msg "\n");
+#define P8_PORE_ETRACE1(msg, arg0) printf("PORE> ERROR: " msg "\n", arg0);
+#define P8_PORE_ETRACE2(msg, arg0, arg1) printf("PORE> ERROR: " msg "\n", arg0, arg1);
+#define P8_PORE_ETRACE3(msg, arg0, arg1, arg2) printf("PORE> ERROR: " msg "\n", arg0, arg1, arg2);
+#define P8_PORE_ETRACE4(msg, arg0, arg1, arg2, arg3) printf("PORE> ERROR: " msg "\n", arg0, arg1, arg2, arg3);
+#define P8_PORE_ETRACE5(msg, arg0, arg1, arg2, arg3, arg4) printf("PORE> ERROR: " msg "\n", arg0, arg1, arg2, arg3, arg4);
+#endif
+/* Used for debug, Cronus/FW should leave these empty */
+#define P8_PORE_DTRACE0(msg)
+#define P8_PORE_DTRACE1(msg, arg0)
+#define P8_PORE_DTRACE2(msg, arg0, arg1)
+#define P8_PORE_DTRACE3(msg, arg0, arg1, arg2)
+#define P8_PORE_DTRACE4(msg, arg0, arg1, arg2, arg3)
+
+/****** Following is only used for debug purposes ******/
+/* FW/Cronus should NOT include this section */
+/* DTRACE - Print debug statements to command line */
+/* FTRACE - Print text PORE instructions of cpureg setup to DEBUG_FILE */
+/*
+#define P8_PORE_DTRACE0(msg) printf("PORE> DEBUG: " msg "\n");
+#define P8_PORE_DTRACE1(msg, arg0) printf("PORE> DEBUG: " msg "\n", arg0);
+#define P8_PORE_DTRACE2(msg, arg0, arg1) printf("PORE> DEBUG: " msg "\n", arg0, arg1);
+#define P8_PORE_DTRACE3(msg, arg0, arg1, arg2) printf("PORE> DEBUG: " msg "\n", arg0, arg1, arg2);
+#define P8_PORE_DTRACE4(msg, arg0, arg1, arg2, arg3) printf("PORE> DEBUG: " msg "\n", arg0, arg1, arg2, arg3);
+*/
+
+/**********************************/
+/***** Endian-ness Handling *****/
+/**********************************/
+/**
+ * Handle byte-swapping if necessary
+ */
+
+/* Default to big-endian format on both sides */
+#define P8_PORE_HOST_TO_BIG32( bit32_int ) htonl(bit32_int)
+#define P8_PORE_BIG32_TO_HOST( bit32_int ) ntohl(bit32_int)
+#define P8_PORE_HOST_TO_BIG16( bit16_int ) htonl(bit16_int)
+#define P8_PORE_BIG16_TO_HOST( bit16_int ) ntohl(bit16_int)
+
+/*
+*************** Do not edit this area ***************
+This section is automatically updated by CVS when you check in this file.
+Be sure to create CVS comments when you commit so that they can be included here.
+
+$Log: p8_pore_api_custom.h,v $
+Revision 1.5 2012/05/22 21:25:21 cmolsen
+Updated to remove FAPI tracing, which is not allowed in plain C files.
+
+Revision 1.4 2012/05/21 14:45:41 cmolsen
+Updated to address Gerrit review II comments about printf() usage.
+
+Revision 1.3 2012/05/15 19:53:38 cmolsen
+Updated to address Gerrit review comments:
+- Hostboot doesn't support printf().
+
+Revision 1.2 2012/04/13 16:45:32 cmolsen
+Includes __HOSTBOOT_MODULE exclude of <netinit/in.h>
+
+Revision 1.1 2011/08/25 12:28:38 yjkim
+initial check in
+
+Revision 1.10 2010/08/30 23:27:17 schwartz
+Added TRACE statements to include specified number of arguments
+Defined branch type constants
+Added constant for last scom op used to check if operation input to gen_scan is valid
+Added mult spr error constant
+Added p7p_pore_gen_wait API
+Changed additional C++ style comments to C style
+Initialized all variables to 0
+Removed FTRACE statements
+Added additional information to trace statements
+Updated gen_scom to use the defined operation constants
+Updated branch gen_relbranch to use defined branch type constants
+Added rc check for calls to p7p_pore_gen_cpureg_status and p7p_pore_span_128byte_boundary subroutines
+
+Revision 1.9 2010/08/30 14:57:54 schwartz
+Removed FTRACE and associated #define statements
+Changed TRACE macros to multiple macros with specified number of args
+
+Revision 1.6 2010/08/26 15:13:34 schwartz
+Fixed more C++ style comments to C style comments
+
+Revision 1.5 2010/06/23 23:06:37 schwartz
+Defined additional trace functions to be used for debugging, not in FW or Cronus
+
+Revision 1.4 2010/05/24 02:34:07 schwartz
+Fixed errors that appear when using -Werrors flag
+Added in cvs logging (hopefully)
+
+
+*/
diff --git a/roms/skiboot/libpore/p8_pore_table_gen_api.H b/roms/skiboot/libpore/p8_pore_table_gen_api.H
new file mode 100644
index 000000000..63081ca50
--- /dev/null
+++ b/roms/skiboot/libpore/p8_pore_table_gen_api.H
@@ -0,0 +1,440 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/hwpf/hwp/build_winkle_images/p8_slw_build/p8_pore_table_gen_api.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2012,2014 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: p8_pore_table_gen_api.H,v 1.27 2014/06/02 18:21:55 cmolsen Exp $
+/*------------------------------------------------------------------------------*/
+/* *! (C) Copyright International Business Machines Corp. 2012 */
+/* *! All Rights Reserved -- Property of IBM */
+/* *! *** *** */
+/*------------------------------------------------------------------------------*/
+/* *! TITLE : p8_pore_table_gen_api.H */
+/* *! DESCRIPTION : Contains all external APIs used by firmware (PHYP) to */
+// generate/modify the P8 PORE SLW image with Ramming and
+// Scomming specific instructions to be executed on exit from
+// Sleep/Winkle. Also contains definitions for the ramming
+// PORE code.
+/* *! OWNER NAME : Michael Olsen Email: cmolsen@us.ibm.com */
+//
+/* *! COMMENTS : *** VERY IMPORTANT *** */
+// The "Shared RAM section", the "Pore RAM section" and the
+// "C-code RAM section" must closely match eachother.
+//
+/*------------------------------------------------------------------------------*/
+
+#ifndef _P8_PORE_TABLE_GEN_API_H
+#define _P8_PORE_TABLE_GEN_API_H
+
+/********************************************************************/
+/* Shared RAM section - begin */
+/* This section MUST perfectly match the "Pore/C-code RAM section". */
+/********************************************************************/
+// Header defs (P8&PORE 64-bit notation where bits are numbered from left-to-right).
+// (Some of these defs are used in the c-specific section further down.)
+// -----------------------------------------------------------------------------
+// Note: SPR register numbers have a swizzle about them per PPC architecture
+// spr(instruction) <- spr5:9 || spr0:4
+//
+// For the PGAS routine, it is assumed that the API does the swizzling upon
+// building the instruction held in this structure
+//
+// Header configuration: CPU Register Operation Header
+// 0 - End: 1=End; 0=More
+// 1 - Reserved
+// 2:3 - Type
+// 00: MTSPR
+// 01: MTMSRD
+// 10: Reserved
+// 11: Reserved
+// 4:13 - SPR number in non-swizzled form (0:9)
+// 14:15 - Reserved for SPR nunmber expansion
+// 16:18 - Thread ID
+// 19:31 - Reserved
+
+#define RAM_HEADER_END_START 0
+#define RAM_HEADER_END_MASK BITS(RAM_HEADER_END_START,1)
+#define RAM_HEADER_TYPE_START 2
+#define RAM_HEADER_TYPE_MASK BITS(RAM_HEADER_TYPE_START,2)
+#define RAM_HEADER_SPRN_START 4
+#define RAM_HEADER_SPRN_MASK BITS(RAM_HEADER_SPRN_START,10)
+#define RAM_HEADER_THREAD_START 16
+#define RAM_HEADER_THREAD_MASK BITS(RAM_HEADER_THREAD_START,3)
+#define RAM_INSTR_START 32
+#define RAM_INSTR_MASK BITS(RAM_INSTR_START,32)
+// MTSPR instr defs
+#define RAM_MTSPR_INSTR_TEMPL ( ( (uint64_t)31<<(63-5) | (uint64_t)467<<(63-30) ) )
+#define RAM_MTSPR_SPR_START 11
+#define RAM_MTSPR_SPR_MASK BITS(RAM_MTSPR_SPR_START,10)
+// Thread align defs
+#define RAM_HEADER_THREAD_RALIGN ( 61-16 ) // 3 Bit shift right amount
+#define RAM_HEADER_THREAD_LALIGN ( 61-16 ) // 3 Bit shift left amount
+/********************************************************************/
+/* Shared RAM section - end */
+/********************************************************************/
+
+
+#ifdef FOR_PORE_RAMMING
+
+// Thread status
+CONST_UINT64_T( PROC_RAS_STAT_10013002 , ULL(0x10013002) );
+
+// TCTL RAS Status (for each thread)
+// Note: the address is not included in the name to ease PGAS indexing
+// of these registers
+CONST_UINT64_T( EX_PERV_TCTL0_R_STAT , ULL(0x10013002) );
+CONST_UINT64_T( EX_PERV_TCTL1_R_STAT , ULL(0x10013012) );
+CONST_UINT64_T( EX_PERV_TCTL2_R_STAT , ULL(0x10013022) );
+CONST_UINT64_T( EX_PERV_TCTL3_R_STAT , ULL(0x10013032) );
+CONST_UINT64_T( EX_PERV_TCTL4_R_STAT , ULL(0x10013042) );
+CONST_UINT64_T( EX_PERV_TCTL5_R_STAT , ULL(0x10013052) );
+CONST_UINT64_T( EX_PERV_TCTL6_R_STAT , ULL(0x10013062) );
+CONST_UINT64_T( EX_PERV_TCTL7_R_STAT , ULL(0x10013072) );
+
+// Thread scratch registers
+// Note: the address is not included in the name to ease PGAS indexing
+// of these registers
+CONST_UINT64_T( EX_PERV_SCRATCH0 , ULL(0x10013283) );
+CONST_UINT64_T( EX_PERV_SCRATCH1 , ULL(0x10013284) );
+CONST_UINT64_T( EX_PERV_SCRATCH2 , ULL(0x10013285) );
+CONST_UINT64_T( EX_PERV_SCRATCH3 , ULL(0x10013286) );
+CONST_UINT64_T( EX_PERV_SCRATCH4 , ULL(0x10013287) );
+CONST_UINT64_T( EX_PERV_SCRATCH5 , ULL(0x10013288) );
+CONST_UINT64_T( EX_PERV_SCRATCH6 , ULL(0x10013289) );
+CONST_UINT64_T( EX_PERV_SCRATCH7 , ULL(0x1001328A) );
+
+// Ramming settings.
+CONST_UINT64_T( RAM_STATUS_REG_AFTER_RAM, 0x5000000000000000);
+CONST_UINT64_T( RAM_COMPLETE_POLLS, 0x0000000000000040);
+
+// mfspr gpr0, scratch0 opcode left-shifted 29 bits, ready for ramming.
+CONST_UINT64_T( MTSPR_SCRATCH0_GPR0_RAM_READY, (0x000000007C1543A6<<29));
+CONST_UINT64_T( MFSPR_GPR0_SCRATCH0_RAM_READY, (0x000000007C1542A6<<29));
+CONST_UINT64_T( MTMSRD_GPR0_RAM_READY, (0x000000007C000164<<29));
+CONST_UINT64_T( MFMSR_GPR0_RAM_READY, (0x000000007C0000A6<<29));
+
+// Predefined MSR content during Ramming
+CONST_UINT64_T( P8_PORE_MSR_DURING_RAM, (0x9000000002802000) );
+
+// "reset" value of SCRATCH0 to ensure it gets updated from GPR0
+CONST_UINT64_T( SCRATCH0_RESET_VALUE, (0xABBA99EBBA33DADA) );
+
+#ifdef __ASSEMBLER__
+
+/***********************************************************************/
+/* Pore RAM section - begin */
+/* This section MUST perfectly match the "Shared/C-code RAM section". */
+/***********************************************************************/
+.set RAM_HEADER, 0
+.set RAM_INSTR, 4
+.set RAM_DATA, 8
+.set RAM_ENTRY_LENGTH, 16
+/***********************************************************************/
+/* Pore RAM section - end */
+/***********************************************************************/
+
+#endif // __ASSEMBLER__
+
+
+#else // Not FOR_PORE_RAMMING
+
+
+//#include <stdio.h>
+#ifndef PPC_HYP
+#include <stdlib.h>
+#endif // PPC_HYP
+#ifndef __P8_PORE_TABLE_GEN_API_C
+#include <p8_pore_api_custom.h>
+#endif
+//#include <stdint.h>
+
+//#include <pore_bitmanip.H>
+// Defining local versions of BITS and BIT
+// Create a multi-bit mask of \a n bits starting at bit \a b
+#define BITS(b, n) ((ULL(0xffffffffffffffff) << (64 - (n))) >> (b))
+#define BITS32(b,n) (uint32_t)((ULL(0xffffffff) << (32 - (n))) >> (b))
+// Create a single bit mask at bit \a b
+#define BIT(b) BITS((b), 1)
+
+// Header defs (C notation where bits are numbered from right-to-left, and reducing to 32-bit)
+#define RAM_HEADER_END_START_C ( 31-RAM_HEADER_END_START+1-1 )
+#define RAM_HEADER_END_MASK_C (uint32_t)(RAM_HEADER_END_MASK>>32)
+#define RAM_HEADER_TYPE_START_C ( 31-RAM_HEADER_TYPE_START+1-2 )
+#define RAM_HEADER_TYPE_MASK_C (uint32_t)(RAM_HEADER_TYPE_MASK>>32)
+#define RAM_HEADER_SPRN_START_C ( 31-RAM_HEADER_SPRN_START+1-10 )
+#define RAM_HEADER_SPRN_MASK_C (uint32_t)(RAM_HEADER_SPRN_MASK>>32)
+#define RAM_HEADER_THREAD_START_C ( 31-RAM_HEADER_THREAD_START+1-3 )
+#define RAM_HEADER_THREAD_MASK_C (uint32_t)(RAM_HEADER_THREAD_MASK>>32)
+// MTSPR instr defs
+#define RAM_MTSPR_INSTR_TEMPL_C ( ( (uint32_t)31<<(31-5) | (uint32_t)467<<(31-30) ) )
+#define RAM_MTSPR_SPR_START_C ( 31-RAM_MTSPR_SPR_START+1-10 )
+//#define RAM_MTSPR_SPR_MASK_C (uint32_t)(BITS(RAM_MTSPR_SPR_START,10)>>32)
+#define RAM_MTSPR_SPR_MASK_C (uint32_t)(RAM_MTSPR_SPR_MASK>>32)
+// MTMSR innstr def
+#define RAM_MTMSRD_INSTR_TEMPL_C ( ( (uint32_t)31<<(31-5) | (uint32_t)178<<(31-30) ) )
+
+/* Other defs needed for ramming and scomming */
+// TOC names
+#define SLW_HOST_REG_VECTOR_TOC_NAME "slw_host_reg_vector"
+#define SLW_HOST_SCOM_NC_VECTOR_TOC_NAME "slw_host_scom_nc_vector"
+#define SLW_HOST_SCOM_L2_VECTOR_TOC_NAME "slw_host_scom_l2_vector"
+#define SLW_HOST_SCOM_L3_VECTOR_TOC_NAME "slw_host_scom_l3_vector"
+
+// Defines for slw_build() to update "runtime_scom" pointers w/pointer to
+// "sub_slw_runtime_scom" subroutines at SLW image build time.
+#define HOST_RUNTIME_SCOM_TOC_NAME "host_runtime_scom" // Null 1st, then fill w/addr of SLW_RUNTIME_SCOM_TOC_NAME
+#define SLW_RUNTIME_SCOM_TOC_NAME "sub_slw_runtime_scom"
+
+// The following two provide TRANSITIONAL SUPPORT only. TO BE REMOVED ASAP.
+#define EX_ENABLE_RUNTIME_SCOM_TOC_NAME "ex_enable_runtime_scom"
+#define SLW_EX_ENABLE_RUNTIME_SCOM_TOC_NAME "sub_slw_ex_enable_runtime_scom"
+
+#define SCAN_MAX_ROTATE_38XXX_NAME "scan_max_rotate_38xxx"
+#define SCAN_ROTATE_DEFAULT 110 // Limit suggested by Tilman.
+#define SCAN_MAX_ROTATE 0x00000FE0
+#define SCAN_MAX_ROTATE_LONG 0x000FFFFF // All 1s in BITS 12->31.
+//#define SCAN_MAX_ROTATE_LONG 0x000000D0 // Experimental max val
+
+#define OVER_SAMPLING_POLL 10
+#define WAITS_POLL_MIN 32
+
+// RAM table defines
+#define XIPSIZE_RAM_ENTRY ( (sizeof(RamTableEntry)+7)/8*8 )
+#define SLW_MAX_CORES 16
+#define SLW_MAX_CPUREGS_CORE 10
+#define SLW_MAX_CPUREGS_THREADS 5
+#define SLW_CORE_THREADS 8
+#define SLW_MAX_CPUREGS_OPS ( SLW_MAX_CPUREGS_CORE + \
+ SLW_CORE_THREADS*SLW_MAX_CPUREGS_THREADS )
+#define SLW_RAM_TABLE_SPACE_PER_CORE ( SLW_MAX_CPUREGS_OPS * XIPSIZE_RAM_ENTRY )
+#define SLW_RAM_TABLE_SIZE ( SLW_MAX_CORES * SLW_RAM_TABLE_SPACE_PER_CORE )
+
+// SPR and MSR values for i_regName
+enum {
+ P8_SPR_HRMOR = 313,
+ P8_SPR_HMEER = 337,
+ P8_SPR_PMICR = 852,
+ P8_SPR_PMCR = 884,
+ P8_SPR_HID0 = 1008,
+ P8_SPR_HID1 = 1009,
+ P8_SPR_HID4 = 1012,
+ P8_SPR_HID5 = 1014,
+ P8_CORE_XTRA8 =10008,
+ P8_CORE_XTRA9 =10009,
+ P8_SPR_HSPRG0 = 304,
+ P8_SPR_LPCR = 318,
+ P8_MSR_MSR = 2000,
+ P8_THRD_XTRA3 =20003,
+ P8_THRD_XTRA4 =20004
+};
+
+// SCOM table defines - Common
+#define XIPSIZE_SCOM_ENTRY 16
+
+// SCOM table defines - Non-cache section
+#define SLW_MAX_SCOMS_NC 32
+#define SLW_SCOM_TABLE_SPACE_PER_CORE_NC ( (SLW_MAX_SCOMS_NC+1)*XIPSIZE_SCOM_ENTRY ) // Add 1 for RNNN IIS
+#define SLW_SCOM_TABLE_SIZE_NC ( SLW_MAX_CORES * SLW_SCOM_TABLE_SPACE_PER_CORE_NC )
+
+// SCOM table defines - L2 section
+#define SLW_MAX_SCOMS_L2 16
+#define SLW_SCOM_TABLE_SPACE_PER_CORE_L2 ( (SLW_MAX_SCOMS_L2+1)*XIPSIZE_SCOM_ENTRY ) // Add 1 for RNNN IIS
+#define SLW_SCOM_TABLE_SIZE_L2 ( SLW_MAX_CORES * SLW_SCOM_TABLE_SPACE_PER_CORE_L2 )
+
+// SCOM table defines - L3 section
+#define SLW_MAX_SCOMS_L3 16
+#define SLW_SCOM_TABLE_SPACE_PER_CORE_L3 ( (SLW_MAX_SCOMS_L3+1)*XIPSIZE_SCOM_ENTRY ) // Add 1 for RNNN IIS
+#define SLW_SCOM_TABLE_SIZE_L3 ( SLW_MAX_CORES * SLW_SCOM_TABLE_SPACE_PER_CORE_L3 )
+
+#define SLW_SCOM_TABLE_SIZE_ALL ( SLW_SCOM_TABLE_SIZE_NC + SLW_SCOM_TABLE_SIZE_L2 + SLW_SCOM_TABLE_SIZE_L3)
+
+// RAM and SCOM sub-section offsets from beginning of .slw section.
+#define SLW_RAM_TABLE_OFFSET 0
+#define SLW_SCOM_TABLE_OFFSET_NC (SLW_RAM_TABLE_OFFSET + SLW_RAM_TABLE_SIZE)
+#define SLW_SCOM_TABLE_OFFSET_L2 (SLW_SCOM_TABLE_OFFSET_NC + SLW_SCOM_TABLE_SIZE_NC)
+#define SLW_SCOM_TABLE_OFFSET_L3 (SLW_SCOM_TABLE_OFFSET_L2 + SLW_SCOM_TABLE_SIZE_L2)
+#define SLW_TABLE_SIZE_ALL (SLW_RAM_TABLE_SIZE + SLW_SCOM_TABLE_SIZE_ALL)
+
+// Enumeration of Scom sections in .slw section.
+enum {
+ P8_SCOM_SECTION_NC = 0,
+ P8_SCOM_SECTION_L2 = 1,
+ P8_SCOM_SECTION_L3 = 2,
+ P8_SCOM_SECTION_MAX_VALUE = 2
+};
+
+// SLW section size (Ensure 128-byte alignment.)
+#define FIXED_SLW_SECTION_SIZE (SLW_TABLE_SIZE_ALL/128+(SLW_TABLE_SIZE_ALL%128+127)/128)*128
+
+// FFDC section size (Ensure 128-byte alignment.)
+#define FIXED_FFDC_SECTION_SIZE 640*(SLW_MAX_CORES+1)
+
+// SCOM/CID masks and ranges
+#define P8_CID_EX_LOW 0x10 // Lowest EX chiplet addr
+#define P8_CID_EX_HIGH 0x1f // Highest EX chiplet addr
+
+// SCOM Operators
+#define P8_PORE_SCOM_FIRST_OP 0 // First supported Scom operation.
+#define P8_PORE_SCOM_APPEND 0 // Add Scom to end of table or at first PORE NOP
+ // instruction, whichever comes first.
+#define P8_PORE_SCOM_REPLACE 1 // Repl 1st matching Scom addr or treat as APPEND
+ // if Scom entry is not found.
+#define P8_PORE_SCOM_OR 2 // Overlay data onto existing Scom by bitwise OR.
+#define P8_PORE_SCOM_AND 3 // Overlay data onto existing Scom by bitwise AND.
+#define P8_PORE_SCOM_NOOP 4 // Replace existing Scom with a PORE NOP instruction,
+ // NNNN.
+#define P8_PORE_SCOM_RESET 5 // Delete all entries for given coreID. Replace with
+ // PORE RET instructions, RNNN.
+#define P8_PORE_SCOM_OR_APPEND 6 // Same as OR but treat as APPEND if Scom entry is
+ // not found.
+#define P8_PORE_SCOM_AND_APPEND 7 // Same as AND but treat as APPEND if Scom entry is
+ // not found.
+#define P8_PORE_SCOM_LAST_OP 7 // Last supported Scom operation.
+
+
+// Enumeration of SLW image build modes.
+enum {
+ P8_SLW_MODEBUILD_IPL = 0,
+ P8_SLW_MODEBUILD_REBUILD = 1,
+ P8_SLW_MODEBUILD_SRAM = 2,
+ P8_SLW_MODEBUILD_MAX_VALUE = 2
+};
+
+
+// Return codes
+#define SLW_RAM_SUCCESS 0
+#define SLW_RAM_HEADERS_NOT_SYNCED 1
+#define SLW_RAM_IMAGE_SIZE_MISMATCH 2
+#define SLW_RAM_TABLE_ENTRY_OVERFLOW 3
+#define SLW_RAM_CODE_ERROR 4
+#define SLW_RAM_INVALID_PARAMETER 5
+#define SLW_RAM_WARNING_TABLE_CONTAMINATION 6
+
+
+#ifndef PPC_HYP
+#ifdef __cplusplus
+extern "C" {
+#endif
+#endif // PPC_HYP
+
+/********************************************************************/
+/* C-code RAM section - begin */
+/* This section MUST perfectly match the "Shared/Pore RAM section". */
+/********************************************************************/
+typedef struct ram_instr_t {
+ uint32_t header;
+ uint32_t instr;
+ uint64_t data;
+} RamTableEntry;
+/********************************************************************/
+/* C-code RAM section - end */
+/********************************************************************/
+
+// SLW supported SPR registers
+typedef struct {
+ const char *name;
+ uint32_t value;
+ uint32_t swizzled;
+} SlwSprRegs;
+
+extern const SlwSprRegs SLW_SPR_REGS[];
+extern const int SLW_SPR_REGS_SIZE;
+
+/* Name: p8_pore_gen_cpureg()
+ * Description: Populates ramming entries in the .slw section
+ * Parameter list: i_image - pointer to SLW mainstore image
+ * i_sizeImage - size of SLW mainstore image
+ * i_regName - unswizzled SPR register value
+ * i_regData - data to write to SPR register
+ * i_coreId - the core ID to operate on
+ * i_threadId - the thread ID to operate on
+ */
+uint32_t p8_pore_gen_cpureg(void *io_image,
+ uint32_t i_sizeImage,
+ uint32_t i_regName,
+ uint64_t i_regData,
+ uint32_t i_coreId,
+ uint32_t i_threadId);
+
+/* Name: p8_pore_gen_scom()
+ * Description: Populates scom entries in the .slw section
+ * Parameter list: i_image - pointer to SLW mainstore image
+ * i_sizeImage - size of SLW mainstore image
+ * i_scomAddr - scom register address
+ * i_coreId - the core ID [0:15]
+ * i_scomData - 64-bit data to put in scom register
+ * i_operation - what to do with the scom data [0:5]
+ * i_section - SCOM section [0,2,3]
+ */
+uint32_t p8_pore_gen_scom(void *io_image,
+ uint32_t i_sizeImage,
+ uint32_t i_scomAddr,
+ uint32_t i_coreId,
+ uint64_t i_scomData,
+ uint32_t i_operation,
+ uint32_t i_section);
+
+
+/* Name: p8_pore_gen_cpureg_fixed()
+ * Description: Populates ramming entries in the .slw section
+ * Parameter list: i_image - pointer to SLW mainstore image
+ * i_modeBuild - 0: HB/IPL mode, 1: PHYP/Rebuild mode, 2: SRAM mode.
+ * i_sizeImage - size of SLW mainstore image
+ * i_regName - unswizzled SPR register value
+ * i_regData - data to write to SPR register
+ * i_coreId - the core ID to operate on
+ * i_threadId - the thread ID to operate on
+ */
+uint32_t p8_pore_gen_cpureg_fixed(void *io_image,
+ uint8_t i_modeBuild,
+ uint32_t i_regName,
+ uint64_t i_regData,
+ uint32_t i_coreId,
+ uint32_t i_threadId);
+
+/* Name: p8_pore_gen_scom_fixed()
+ * Description: Populates scom entries in the .slw section
+ * Parameter list: i_image - pointer to SLW mainstore image
+ * i_modeBuild - 0: HB/IPL mode, 1: PHYP/Rebuild mode, 2: SRAM mode.
+ * i_scomAddr - scom register address
+ * i_coreId - the core ID [0:15]
+ * i_scomData - 64-bit data to put in scom register
+ * i_operation - what to do with the scom data [0:5]
+ * i_section - 0: General Scoms, 1: L2 cache, 2: L3 cache
+ */
+uint32_t p8_pore_gen_scom_fixed(void *io_image,
+ uint8_t i_modeBuild,
+ uint32_t i_scomAddr,
+ uint32_t i_coreId,
+ uint64_t i_scomData,
+ uint32_t i_operation,
+ uint32_t i_section);
+
+#ifndef PPC_HYP
+#ifdef __cplusplus
+}
+#endif
+#endif // PPC_HYP
+
+#endif // FOR_PORE_RAMMING
+
+#endif // _P8_PORE_TABLE_GEN_API_H
diff --git a/roms/skiboot/libpore/p8_pore_table_gen_api_fixed.C b/roms/skiboot/libpore/p8_pore_table_gen_api_fixed.C
new file mode 100644
index 000000000..9e816ecd1
--- /dev/null
+++ b/roms/skiboot/libpore/p8_pore_table_gen_api_fixed.C
@@ -0,0 +1,846 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/hwpf/hwp/build_winkle_images/p8_slw_build/p8_pore_table_gen_api_fixed.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2013,2014 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: p8_pore_table_gen_api_fixed.C,v 1.15 2014/05/30 20:31:24 cmolsen Exp $
+//
+/*------------------------------------------------------------------------------*/
+/* *! (C) Copyright International Business Machines Corp. 2012 */
+/* *! All Rights Reserved -- Property of IBM */
+/* *! *** *** */
+/*------------------------------------------------------------------------------*/
+/* *! TITLE : p8_pore_table_gen_api_fixed.C */
+/* *! DESCRIPTION : PORE SLW table generaion APIs */
+/* *! OWNER NAME : Michael Olsen Email: cmolsen@us.ibm.com */
+//
+/* *! USAGE : To build for PHYP command-line - */
+/* buildecmdprcd -C "p8_pore_table_gen_api_fixed.C" -c "p8_pore_table_static_data.c,sbe_xip_image.c,pore_inline_assembler.c" -u "SLW_COMMAND_LINE_RAM" p8_pore_table_gen_api_fixed_main.C */
+//
+/* *! COMMENTS : - The DYNAMIC_RAM_TABLE_PPD was dropped in v1.12 of this */
+/* code. See v1.12 for explanation and code implementation. */
+//
+/*------------------------------------------------------------------------------*/
+
+#define __P8_PORE_TABLE_GEN_API_C
+#include <p8_delta_scan_rw.h>
+#include <p8_pore_api_custom.h>
+#include <p8_pore_table_gen_api.H>
+
+/*
+// io_image - pointer to SLW image
+// i_modeBuild - 0: HB/IPL mode, 1: PHYP/Rebuild mode, 2: SRAM mode.
+// i_regName - unswizzled enum SPR value (NOT a name)
+// i_regData - data to write
+// i_coreIndex - core ID = [0:15]
+// i_threadIndex - thread to operate on = [0:7].
+*/
+uint32_t p8_pore_gen_cpureg_fixed( void *io_image,
+ uint8_t i_modeBuild,
+ uint32_t i_regName,
+ uint64_t i_regData,
+ uint32_t i_coreId,
+ uint32_t i_threadId)
+{
+ uint32_t rc=0, rcLoc=0, iCount=0;
+ int i=0, iReg=-1;
+ uint64_t xipSlwRamSection;
+ void *hostSlwRamSection;
+ void *hostSlwSectionFixed;
+ uint64_t xipRamTableThis;
+ void *hostRamVector;
+ void *hostRamTableThis=NULL;
+ void *hostRamEntryThis=NULL, *hostRamEntryNext=NULL;
+ uint8_t bNewTable=0, bFound=0;
+ uint8_t bEntryEnd=1, headerType=0;
+ SbeXipSection xipSection;
+ SbeXipItem xipTocItem;
+ RamTableEntry ramEntryThis, *ramEntryNext;
+ uint32_t sprSwiz=0;
+ uint8_t bReplaceEntry=0;
+ uint32_t headerNext=0;
+ uint32_t instrNext=0;
+
+
+ // -------------------------------------------------------------------------
+ // Validate Ramming parameters.
+ //
+ // ...check mode build
+ if (i_modeBuild>P8_SLW_MODEBUILD_MAX_VALUE) {
+ MY_ERR("modeBuild=%i invalid. Valid range is [0;%i].",
+ i_modeBuild,P8_SLW_MODEBUILD_MAX_VALUE);
+ rcLoc = 1;
+ }
+ // ...check register value
+ bFound = 0;
+ for (i=0;i<SLW_SPR_REGS_SIZE;i++) {
+ if (i_regName==SLW_SPR_REGS[i].value) {
+ bFound = 1;
+ iReg = i;
+ break;
+ }
+ }
+ if (!bFound) {
+ MY_ERR("Register value = %i is not supported.\n",i_regName);
+ MY_ERR("The following registers are supported:\n");
+ for (i=0;i<SLW_SPR_REGS_SIZE;i++)
+ MY_ERR("\t(%s,%i)\n",SLW_SPR_REGS[i].name,SLW_SPR_REGS[i].value);
+ rcLoc = 1;
+ }
+ // ...check core ID
+ if (i_coreId>=SLW_MAX_CORES) {
+ MY_ERR("Core ID = %i is not within valid range of [0;%i]\n",i_coreId,SLW_MAX_CORES-1);
+ rcLoc = 1;
+ }
+ // ...check thread ID
+ // - ensure it's zero if SPR is not thread scoped, i.e. if SPR is core scoped.
+ // - error out if threadId exceed max num of threads.
+ if (i_regName!=P8_SPR_HSPRG0 && i_regName!=P8_SPR_LPCR && i_regName!=P8_MSR_MSR) {
+ i_threadId = 0;
+ }
+ if (i_threadId>=SLW_CORE_THREADS) {
+ MY_ERR("Thread ID = %i is not within valid range of [0;%i]\n",i_threadId,SLW_CORE_THREADS-1);
+ rcLoc = 1;
+ }
+ if (rcLoc)
+ return IMGBUILD_ERR_RAM_INVALID_PARM;
+ rcLoc = 0;
+
+ // -------------------------------------------------------------------------
+ // Check slw section location and size. (Mainly needed for fixed image.)
+ //
+ if (i_modeBuild==P8_SLW_MODEBUILD_IPL ||
+ i_modeBuild==P8_SLW_MODEBUILD_REBUILD) { // Fixed image.
+ hostSlwSectionFixed = (void*)( (uintptr_t)io_image +
+ FIXED_SLW_IMAGE_SIZE -
+ FIXED_FFDC_SECTION_SIZE -
+ FIXED_SLW_SECTION_SIZE );
+ // Even though we shouldn't call this api during a rebuild, it should be
+ // safe to do so in this particular case since none of the info requested
+ // is supposed to be moved during a rebuild.
+ rc = sbe_xip_get_section( io_image, SBE_XIP_SECTION_SLW, &xipSection);
+ if (rc) {
+ MY_ERR("Probably invalid section name for SBE_XIP_SECTION_SLW.\n");
+ return IMGBUILD_ERR_GET_SECTION;
+ }
+ hostSlwRamSection = (void*)((uintptr_t)io_image + xipSection.iv_offset);
+ if (hostSlwSectionFixed!=hostSlwRamSection) {
+ MY_ERR("hostSlwSectionFixed != hostSlwRamSection(from image api).\n");
+ return IMGBUILD_ERR_RAM_HDRS_NOT_SYNCED;
+ }
+ else {
+ MY_INF("hostSlwSectionFixed == hostSlwRamSection(from image api).\n");
+ }
+ }
+ else { // SRAM non-fixed image.
+ rc = sbe_xip_get_section( io_image, SBE_XIP_SECTION_SLW, &xipSection);
+ if (rc) {
+ MY_ERR("Probably invalid section name for SBE_XIP_SECTION_SLW.\n");
+ return IMGBUILD_ERR_GET_SECTION;
+ }
+ hostSlwRamSection = (void*)((uintptr_t)io_image + xipSection.iv_offset);
+ sbe_xip_host2pore( io_image, hostSlwRamSection, &xipSlwRamSection);
+ }
+
+ // -------------------------------------------------------------------------
+ // Cross check SPR register and table defines
+ //
+ if (SLW_SPR_REGS_SIZE!=(SLW_MAX_CPUREGS_CORE+SLW_MAX_CPUREGS_THREADS)) {
+ MY_ERR("Defines in *.H header file not in sync.\n");
+ return IMGBUILD_ERR_RAM_HDRS_NOT_SYNCED;
+ }
+ if (xipSection.iv_size!=FIXED_SLW_SECTION_SIZE) {
+ MY_ERR("Fixed SLW table size in *.H header file differs from SLW section size in image.\n");
+ MY_ERR("Check code or image version.\n");
+ return IMGBUILD_ERR_RAM_HDRS_NOT_SYNCED;
+ }
+
+ // -------------------------------------------------------------------------
+ // Summarize parameters and checking results.
+ //
+ MY_INF("Input parameter checks - OK\n");
+ MY_INF("\tMode build= %i\n",i_modeBuild);
+ MY_INF("\tRegister = (%s,%i)\n",SLW_SPR_REGS[iReg].name,SLW_SPR_REGS[iReg].value);
+ MY_INF("\tCore ID = %i\n",i_coreId);
+ MY_INF("\tThread ID = %i\n",i_threadId);
+ MY_INF("Image validation and size checks - OK\n");
+ MY_INF("\tSLW section size= %i\n",xipSection.iv_size);
+
+ // -------------------------------------------------------------------------
+ // Locate RAM vector and locate RAM table associated with "This" core ID.
+ //
+ if (i_modeBuild==P8_SLW_MODEBUILD_IPL ||
+ i_modeBuild==P8_SLW_MODEBUILD_REBUILD) { // Fixed image.
+ hostRamTableThis = (void*)( (uintptr_t)io_image +
+ FIXED_SLW_IMAGE_SIZE -
+ FIXED_FFDC_SECTION_SIZE -
+ FIXED_SLW_SECTION_SIZE +
+ SLW_RAM_TABLE_SPACE_PER_CORE*i_coreId );
+ if (*(uintptr_t*)hostRamTableThis) { // Table content NOT empty.
+ bNewTable = 0; // So, NOT new table.
+ }
+ else { // Table content empty.
+ bNewTable = 1; // So, new table.
+ }
+ }
+ else { // SRAM non-fixed image.
+ rc = sbe_xip_find( io_image, SLW_HOST_REG_VECTOR_TOC_NAME, &xipTocItem);
+ if (rc) {
+ MY_ERR("Probably invalid key word for SLW_HOST_REG_VECTOR_TOC_NAME.\n");
+ return IMGBUILD_ERR_KEYWORD_NOT_FOUND;
+ }
+ sbe_xip_pore2host( io_image, xipTocItem.iv_address, &hostRamVector);
+ xipRamTableThis = myRev64(*((uint64_t*)hostRamVector + i_coreId));
+ if (xipRamTableThis) {
+ sbe_xip_pore2host( io_image, xipRamTableThis, &hostRamTableThis);
+ bNewTable = 0;
+ }
+ else {
+ hostRamTableThis = (void*)( (uintptr_t)hostSlwRamSection +
+ SLW_RAM_TABLE_SPACE_PER_CORE*i_coreId );
+ bNewTable = 1;
+ }
+ }
+
+
+ // -------------------------------------------------------------------------
+ // Create most of the RAM entry, so it can be used to find a potential existing entry to
+ // replace. Postpone decision about bEntryEnd and assume its zero for now (not end).
+ //
+ if (i_regName==P8_MSR_MSR) {
+ // ...make the MSR header
+ headerType = 0x1; // MTMSRD header.
+ ramEntryThis.header = ( ((uint32_t)headerType) << RAM_HEADER_TYPE_START_C & RAM_HEADER_TYPE_MASK_C ) |
+ ( i_threadId << RAM_HEADER_THREAD_START_C & RAM_HEADER_THREAD_MASK_C );
+ // ...make the MSR instr
+ ramEntryThis.instr = RAM_MTMSRD_INSTR_TEMPL_C;
+ }
+ else {
+ // ...make the SPR header
+ headerType = 0x0; // MTSPR header.
+ ramEntryThis.header = ( ((uint32_t)headerType) << RAM_HEADER_TYPE_START_C & RAM_HEADER_TYPE_MASK_C ) |
+ ( i_regName << RAM_HEADER_SPRN_START_C & RAM_HEADER_SPRN_MASK_C ) |
+ ( i_threadId << RAM_HEADER_THREAD_START_C & RAM_HEADER_THREAD_MASK_C );
+ // ...make the SPR instr
+ sprSwiz = i_regName>>5 | (i_regName & 0x0000001f)<<5;
+ if (sprSwiz!=SLW_SPR_REGS[iReg].swizzled) {
+ MY_ERR("Inconsistent swizzle rules implemented. Check code. Dumping data.\n");
+ MY_ERR("\tsprSwiz (on-the-fly-calc)=%i\n",sprSwiz);
+ MY_ERR("\tSLW_SPR_REGS[%i].swizzled=%i\n",iReg,SLW_SPR_REGS[iReg].swizzled);
+ return IMGBUILD_ERR_RAM_CODE;
+ }
+ ramEntryThis.instr = RAM_MTSPR_INSTR_TEMPL_C | ( ( sprSwiz<<RAM_MTSPR_SPR_START_C ) & RAM_MTSPR_SPR_MASK_C );
+ }
+ // ...make the data
+ ramEntryThis.data = i_regData;
+
+
+
+ // -------------------------------------------------------------------------
+ // Determine insertion point of new RAM entry, hostRamEntryThis. The possibilities are:
+ // - New table => First entry
+ // - Existing Ram entry => Replace said entry
+ // - Existing table, new Ram entry => Last entry
+ //
+ bReplaceEntry = 0;
+ if (bNewTable) {
+ // Append to beginning of agreed upon static Ram table position for this coreId.
+ bEntryEnd = 1;
+ ramEntryThis.header = ( ((uint32_t)bEntryEnd) << RAM_HEADER_END_START_C & RAM_HEADER_END_MASK_C ) |
+ ramEntryThis.header;
+ hostRamEntryThis = hostRamTableThis;
+ if (i_modeBuild==P8_SLW_MODEBUILD_SRAM) {
+ // Update RAM vector (since it is currently NULL)
+ *((uint64_t*)hostRamVector + i_coreId) =
+ myRev64( xipSlwRamSection + SLW_RAM_TABLE_SPACE_PER_CORE*i_coreId );
+ }
+ }
+ else {
+ // Append at end of existing Ram table for this coreId
+ // or
+ // Replace an existing Ram entry
+ hostRamEntryNext = hostRamTableThis;
+ ramEntryNext = (RamTableEntry*)hostRamEntryNext;
+ headerNext = myRev32(ramEntryNext->header);
+ instrNext = myRev32(ramEntryNext->instr);
+ iCount = 1;
+ // Examine all entries, except last entry.
+ while ((headerNext & RAM_HEADER_END_MASK_C)==0 && bReplaceEntry==0) {
+ if (iCount>=SLW_MAX_CPUREGS_OPS) {
+ MY_ERR("Bad table! Header end bit not found and RAM table full (=%i entries).\n",SLW_MAX_CPUREGS_OPS);
+ return IMGBUILD_ERR_RAM_TABLE_END_NOT_FOUND;
+ }
+ if (ramEntryThis.header==headerNext && ramEntryThis.instr==instrNext) {
+ // Its a replacement. Stop searching. Go do the replacement.
+ bReplaceEntry = 1;
+ hostRamEntryThis = hostRamEntryNext;
+ }
+ else {
+ hostRamEntryNext = (void*)((uint8_t*)hostRamEntryNext + XIPSIZE_RAM_ENTRY);
+ ramEntryNext = (RamTableEntry*)hostRamEntryNext;
+ headerNext = myRev32(ramEntryNext->header);
+ instrNext = myRev32(ramEntryNext->instr);
+ iCount++;
+ }
+ }
+ if (bReplaceEntry==0) {
+ // Examine the last entry.
+ if (headerNext & RAM_HEADER_END_MASK_C) {
+ // Now we know for sure that our new Ram entry will also be the last, either as a
+ // replace or append. So put the end bit into the new entry.
+ bEntryEnd = 1;
+ ramEntryThis.header = ( ((uint32_t)bEntryEnd) << RAM_HEADER_END_START_C & RAM_HEADER_END_MASK_C ) |
+ ramEntryThis.header;
+ // Determine if to replace or append.
+ if (ramEntryThis.header==headerNext && ramEntryThis.instr==instrNext) {
+ // Its a replacement. And it would be legal to replace the very last Ram in a completely full table.
+ if (iCount<=SLW_MAX_CPUREGS_OPS) {
+ bReplaceEntry = 1;
+ hostRamEntryThis = hostRamEntryNext;
+ }
+ else {
+ MY_ERR("RAM table is full. Max %i entries allowed.\n",SLW_MAX_CPUREGS_OPS);
+ return IMGBUILD_ERR_RAM_TABLE_FULL;
+ }
+ }
+ else {
+ // Its an append. Make sure there's room for one more Ram entry.
+ if (iCount<SLW_MAX_CPUREGS_OPS) {
+ // Zero out the end bit in last entrys header (which will now be 2nd last).
+ ramEntryNext->header = ramEntryNext->header & myRev32(~RAM_HEADER_END_MASK_C);
+ hostRamEntryThis = (void*)((uint8_t*)hostRamEntryNext + XIPSIZE_RAM_ENTRY);
+ }
+ else {
+ MY_ERR("RAM table is full. Max %i entries allowed.\n",SLW_MAX_CPUREGS_OPS);
+ return IMGBUILD_ERR_RAM_TABLE_FULL;
+ }
+ }
+ }
+ else {
+ MY_ERR("We should never get here. Check code. Dumping data:\n");
+ MY_ERR("myRev32(ramEntryNext->header) = 0x%08x\n",myRev32(ramEntryNext->header));
+ MY_ERR("RAM_HEADER_END_MASK_C = 0x%08x\n",RAM_HEADER_END_MASK_C);
+ return IMGBUILD_ERR_RAM_CODE;
+ }
+ }
+ }
+
+
+ // Summarize new table entry data
+ MY_INF("New table entry data (host format):\n");
+ MY_INF("\theader = 0x%08x\n",ramEntryThis.header);
+ MY_INF("\tinstr = 0x%08x\n",ramEntryThis.instr);
+ MY_INF("\tdata = 0x%016llx\n",ramEntryThis.data);
+
+ // -------------------------------------------------------------------------
+ // Insert the new RAM entry into the table in BE format.
+ //
+ ramEntryNext = (RamTableEntry*)hostRamEntryThis;
+ // ...some redundant checking
+ if (bNewTable) {
+ // For any new table, the insertion location should be clean. We check for this here.
+ if (myRev32(ramEntryNext->header)!=0) {
+ MY_ERR("WARNING : Table entry location should be empty for a new table. Check code and image. Dumping data:\n");
+ MY_ERR("\theader = 0x%08x\n",myRev32(ramEntryNext->header));
+ MY_ERR("\tinstr = 0x%08x\n",myRev32(ramEntryNext->instr));
+ MY_ERR("\tdata = 0x%016llx\n",myRev64(ramEntryNext->data));
+ rc = IMGBUILD_WARN_RAM_TABLE_CONTAMINATION;
+ }
+ }
+ // ..insert the new Ram entry.
+ ramEntryNext->header = myRev32(ramEntryThis.header);
+ ramEntryNext->instr = myRev32(ramEntryThis.instr);
+ ramEntryNext->data = myRev64(ramEntryThis.data);
+
+ return rc;
+}
+
+
+/*
+// io_image - Pointer to SLW image.
+// i_modeBuild - 0: HB/IPL mode, 1: PHYP/Rebuild mode, 2: SRAM mode.
+// i_scomAddr - Scom address.
+// i_coreId - The core ID [0:15].
+// i_scomData - Data to write to scom register.
+// i_operation - What to do with the scom addr and data.
+// i_section - 0: General Scoms, 1: L2 cache, 2: L3 cache.
+*/
+uint32_t p8_pore_gen_scom_fixed(void *io_image,
+ uint8_t i_modeBuild,
+ uint32_t i_scomAddr,
+ uint32_t i_coreId, // [0:15]
+ uint64_t i_scomData,
+ uint32_t i_operation, // [0:7]
+ uint32_t i_section) // [0,1,2]
+{
+ uint32_t rc=0, rcLoc=0, iEntry=0;
+ uint32_t chipletId=0;
+ uint32_t operation=0;
+ uint32_t entriesCount=0, entriesMatch=0, entriesNOP=0;
+ void *hostSlwSection;
+ void *hostSlwSectionFixed;
+ uint64_t xipScomTableThis;
+ void *hostScomVector, *hostScomTableThis;
+ void *hostScomEntryNext; // running entry pointer
+ void *hostScomEntryMatch=NULL; // pointer to entry that matches scomAddr
+ void *hostScomEntryRET=NULL; // pointer to first return instr after table
+ void *hostScomEntryNOP=NULL; // pointer to first nop IIS
+ uint8_t bufIIS[XIPSIZE_SCOM_ENTRY], bufNOP[4], bufRET[4];
+ SbeXipSection xipSection;
+ SbeXipItem xipTocItem;
+ PoreInlineContext ctx;
+
+ // -------------------------------------------------------------------------
+ // Validate Scom parameters.
+ //
+ // ...check if valid Scom register (is there anything we can do here to check?)
+ // Skipping check. We blindly trust caller.
+ //
+ // ...check mode build
+ if (i_modeBuild>P8_SLW_MODEBUILD_MAX_VALUE) {
+ MY_ERR("modeBuild=%i invalid. Valid range is [0;%i].",
+ i_modeBuild,P8_SLW_MODEBUILD_MAX_VALUE);
+ rcLoc = 1;
+ }
+ // ...check Scom operation
+ if (i_operation>P8_PORE_SCOM_LAST_OP) {
+ MY_ERR("Scom operation = %i is not within valid range of [%d;%d]\n",
+ i_operation, P8_PORE_SCOM_FIRST_OP, P8_PORE_SCOM_LAST_OP);
+ rcLoc = 1;
+ }
+ // ...check that core ID corresponds to valid chiplet ID
+ chipletId = i_coreId + P8_CID_EX_LOW;
+ if (chipletId<P8_CID_EX_LOW || chipletId>P8_CID_EX_HIGH) {
+ MY_ERR("Chiplet ID = 0x%02x is not within valid range of [0x%02x;0x%02x]\n",
+ chipletId, P8_CID_EX_LOW, P8_CID_EX_HIGH);
+ rcLoc = 1;
+ }
+ if (rcLoc)
+ return IMGBUILD_ERR_SCOM_INVALID_PARM;
+ rcLoc = 0;
+
+ // -------------------------------------------------------------------------
+ // Check slw section location and size. (Mainly needed for fixed image.)
+ //
+ if (i_modeBuild==P8_SLW_MODEBUILD_IPL ||
+ i_modeBuild==P8_SLW_MODEBUILD_REBUILD) { // Fixed image.
+ hostSlwSectionFixed = (void*)( (uintptr_t)io_image +
+ FIXED_SLW_IMAGE_SIZE -
+ FIXED_FFDC_SECTION_SIZE -
+ FIXED_SLW_SECTION_SIZE );
+ // Even though we shouldn't call this api during a rebuild, it should be
+ // safe to do so in this particular case since none of the info requested
+ // is supposed to be moved during a rebuild.
+ rc = sbe_xip_get_section( io_image, SBE_XIP_SECTION_SLW, &xipSection);
+ if (rc) {
+ MY_ERR("Probably invalid section name for SBE_XIP_SECTION_SLW.\n");
+ return IMGBUILD_ERR_GET_SECTION;
+ }
+ hostSlwSection = (void*)((uintptr_t)io_image + xipSection.iv_offset);
+ if (hostSlwSectionFixed!=hostSlwSection) {
+ MY_ERR("hostSlwSectionFixed != hostSlwSection(from image api).\n");
+ return IMGBUILD_ERR_SCOM_HDRS_NOT_SYNCD;
+ }
+ else {
+ MY_INF("hostSlwSectionFixed == hostSlwSection(from image api).\n");
+ }
+ }
+ else { // SRAM non-fixed image.
+ rc = sbe_xip_get_section( io_image, SBE_XIP_SECTION_SLW, &xipSection);
+ if (rc) {
+ MY_ERR("Probably invalid section name for SBE_XIP_SECTION_SLW.\n");
+ return IMGBUILD_ERR_GET_SECTION;
+ }
+ hostSlwSection = (void*)((uintptr_t)io_image + xipSection.iv_offset);
+ }
+
+ // -------------------------------------------------------------------------
+ // Check .slw section size and cross-check w/header define.
+ //
+ if (xipSection.iv_size!=FIXED_SLW_SECTION_SIZE) {
+ MY_ERR("SLW table size in *.H header file (=%ld) differs from SLW section size in image (=%i).\n",FIXED_SLW_SECTION_SIZE,xipSection.iv_size);
+ MY_ERR("Check code or image version.\n");
+ return IMGBUILD_ERR_SCOM_HDRS_NOT_SYNCD;
+ }
+
+ // -------------------------------------------------------------------------
+ // Summarize parameters and checking results.
+ //
+ MY_INF("Input parameter checks - OK\n");
+ MY_INF("\tRegister = 0x%08x\n",i_scomAddr);
+ MY_INF("\tOperation = %i\n",i_operation);
+ MY_INF("\tSection = %i\n",i_section);
+ MY_INF("\tCore ID = %i\n",i_coreId);
+ MY_INF("Image validation and size checks - OK\n");
+ MY_INF("\tSLW section size= %i\n",xipSection.iv_size);
+
+ // -------------------------------------------------------------------------
+ // Locate Scom vector according to i_section and then locate Scom table
+ // associated with "This" core ID.
+ //
+ if (i_modeBuild==P8_SLW_MODEBUILD_IPL ||
+ i_modeBuild==P8_SLW_MODEBUILD_REBUILD) { // Fixed image.
+ switch (i_section) {
+ case P8_SCOM_SECTION_NC:
+ hostScomTableThis = (void*)( (uintptr_t)hostSlwSection +
+ SLW_RAM_TABLE_SIZE +
+ SLW_SCOM_TABLE_SPACE_PER_CORE_NC*i_coreId );
+ break;
+ case P8_SCOM_SECTION_L2:
+ hostScomTableThis = (void*)( (uintptr_t)hostSlwSection +
+ SLW_RAM_TABLE_SIZE +
+ SLW_SCOM_TABLE_SIZE_NC +
+ SLW_SCOM_TABLE_SPACE_PER_CORE_L2*i_coreId );
+ break;
+ case P8_SCOM_SECTION_L3:
+ hostScomTableThis = (void*)( (uintptr_t)hostSlwSection +
+ SLW_RAM_TABLE_SIZE +
+ SLW_SCOM_TABLE_SIZE_NC +
+ SLW_SCOM_TABLE_SIZE_L2 +
+ SLW_SCOM_TABLE_SPACE_PER_CORE_L3*i_coreId );
+ break;
+ default:
+ MY_ERR("Invalid value for i_section (=%i).\n",i_section);
+ MY_ERR("Valid values for i_section = [%i,%i,%i].\n",
+ P8_SCOM_SECTION_NC,P8_SCOM_SECTION_L2,P8_SCOM_SECTION_L3);
+ return IMGBUILD_ERR_SCOM_INVALID_SUBSECTION;
+ break;
+ }
+ }
+ else { // SRAM non-fixed image.
+ switch (i_section) {
+ case P8_SCOM_SECTION_NC:
+ rc = sbe_xip_find( io_image, SLW_HOST_SCOM_NC_VECTOR_TOC_NAME, &xipTocItem);
+ if (rc) {
+ MY_ERR("Probably invalid key word for SLW_HOST_SCOM_NC_VECTOR_TOC_NAME.\n");
+ return IMGBUILD_ERR_KEYWORD_NOT_FOUND;
+ }
+ break;
+ case P8_SCOM_SECTION_L2:
+ rc = sbe_xip_find( io_image, SLW_HOST_SCOM_L2_VECTOR_TOC_NAME, &xipTocItem);
+ if (rc) {
+ MY_ERR("Probably invalid key word for SLW_HOST_SCOM_L2_VECTOR_TOC_NAME.\n");
+ return IMGBUILD_ERR_KEYWORD_NOT_FOUND;
+ }
+ break;
+ case P8_SCOM_SECTION_L3:
+ rc = sbe_xip_find( io_image, SLW_HOST_SCOM_L3_VECTOR_TOC_NAME, &xipTocItem);
+ if (rc) {
+ MY_ERR("Probably invalid key word for SLW_HOST_SCOM_L3_VECTOR_TOC_NAME.\n");
+ return IMGBUILD_ERR_KEYWORD_NOT_FOUND;
+ }
+ break;
+ default:
+ MY_ERR("Invalid value for i_section (=%i).\n",i_section);
+ MY_ERR("Valid values for i_section = [%i,%i,%i].\n",
+ P8_SCOM_SECTION_NC,P8_SCOM_SECTION_L2,P8_SCOM_SECTION_L3);
+ return IMGBUILD_ERR_SCOM_INVALID_SUBSECTION;
+ }
+ MY_INF("xipTocItem.iv_address = 0x%016llx\n",xipTocItem.iv_address);
+ sbe_xip_pore2host( io_image, xipTocItem.iv_address, &hostScomVector);
+ MY_INF("hostScomVector = 0x%016llx\n",(uint64_t)hostScomVector);
+ xipScomTableThis = myRev64(*((uint64_t*)hostScomVector + i_coreId));
+ MY_INF("xipScomTableThis = 0x%016llx\n",xipScomTableThis);
+ if (xipScomTableThis) {
+ sbe_xip_pore2host( io_image, xipScomTableThis, &hostScomTableThis);
+ }
+ else { // Should never be here.
+ MY_ERR("Code or image bug. Scom vector table entries should never be null.\n");
+ return IMGBUILD_ERR_CHECK_CODE;
+ }
+ }
+
+ //
+ // Determine where to place/do Scom action and if entry already exists.
+ // Insertion rules:
+ // - If entry doesn't exist, insert at first NOP. (Note that if you don't do
+ // this, then the table might potentially overflow since the max table size
+ // doesn't include NOP entries.)
+ // - If no NOP found, insert at first RET.
+ //
+
+ //----------------------------------------------------------------------------
+ // 1. Create search strings for addr, nop and ret.
+ //----------------------------------------------------------------------------
+ // Note, the following IIS will also be used in case of
+ // - i_operation==append
+ // - i_operation==replace
+ pore_inline_context_create( &ctx, (void*)bufIIS, XIPSIZE_SCOM_ENTRY, 0, 0);
+ pore_LS( &ctx, P1, chipletId);
+ pore_STI( &ctx, i_scomAddr, P1, i_scomData);
+ if (ctx.error > 0) {
+ MY_ERR("pore_LS or _STI generated rc = %d", ctx.error);
+ return IMGBUILD_ERR_PORE_INLINE_ASM;
+ }
+ pore_inline_context_create( &ctx, (void*)bufRET, 4, 0, 0);
+ pore_RET( &ctx);
+ if (ctx.error > 0) {
+ MY_ERR("pore_RET generated rc = %d", ctx.error);
+ return IMGBUILD_ERR_PORE_INLINE_ASM;
+ }
+ pore_inline_context_create( &ctx, (void*)bufNOP, 4, 0, 0);
+ pore_NOP( &ctx);
+ if (ctx.error > 0) {
+ MY_ERR("pore_NOP generated rc = %d", ctx.error);
+ return IMGBUILD_ERR_PORE_INLINE_ASM;
+ }
+
+ //----------------------------------------------------------------------------
+ // 2. Search for addr and nop in relevant coreId table until first RET.
+ //----------------------------------------------------------------------------
+ // Note:
+ // - We go through ALL entries until first RET instr. We MUST find a RET instr,
+ // though we don't check for overrun until later. (Could be improved.)
+ // - Count number of entries, incl the NOOPs, until we find an RET.
+ // - The STI(+SCOM_addr) opcode is in the 2nd word of the Scom entry.
+ // - For an append operation, if a NOP is found (before a RET obviously), the
+ // SCOM is replacing that NNNN sequence.
+ hostScomEntryNext = hostScomTableThis;
+ MY_INF("hostScomEntryNext (addr): 0x%016llx\n ",(uint64_t)hostScomEntryNext);
+ while (memcmp(hostScomEntryNext, bufRET, sizeof(uint32_t))) {
+ entriesCount++;
+ MY_INF("Number of SCOM entries: %i\n ",entriesCount);
+ if (*((uint32_t*)bufIIS+1)==*((uint32_t*)hostScomEntryNext+1) && entriesMatch==0) {// +1 skips 1st word in Scom entry (which loads the PC in an LS operation.)
+ hostScomEntryMatch = hostScomEntryNext;
+ entriesMatch++;
+ }
+ if (memcmp(hostScomEntryNext, bufNOP, sizeof(uint32_t))==0 && entriesNOP==0) {
+ hostScomEntryNOP = hostScomEntryNext;
+ entriesNOP++;
+ }
+ hostScomEntryNext = (void*)((uintptr_t)hostScomEntryNext + XIPSIZE_SCOM_ENTRY);
+ }
+ hostScomEntryRET = hostScomEntryNext; // The last EntryNext is always the first RET.
+
+ //----------------------------------------------------------------------------
+ // 3. Qualify (translate) operation and IIS.
+ //----------------------------------------------------------------------------
+ if (i_operation==P8_PORE_SCOM_APPEND)
+ {
+ operation = i_operation;
+ }
+ else if (i_operation==P8_PORE_SCOM_REPLACE)
+ {
+ if (hostScomEntryMatch)
+ // ... do a replace
+ operation = i_operation;
+ else
+ // ... do an append
+ operation = P8_PORE_SCOM_APPEND;
+ }
+ else if (i_operation==P8_PORE_SCOM_NOOP)
+ {
+ // ...overwrite earlier bufIIS from the search step
+ pore_inline_context_create( &ctx, (void*)bufIIS, XIPSIZE_SCOM_ENTRY, 0, 0);
+ pore_NOP( &ctx);
+ pore_NOP( &ctx);
+ pore_NOP( &ctx);
+ pore_NOP( &ctx);
+ if (ctx.error > 0) {
+ MY_ERR("*** _NOP generated rc = %d", ctx.error);
+ return IMGBUILD_ERR_PORE_INLINE_ASM;
+ }
+ operation = i_operation;
+ }
+ else if ( i_operation==P8_PORE_SCOM_AND ||
+ i_operation==P8_PORE_SCOM_OR )
+ {
+ operation = i_operation;
+ }
+ else if ( i_operation==P8_PORE_SCOM_AND_APPEND )
+ {
+ if (hostScomEntryMatch)
+ // ... do the AND on existing Scom
+ operation = P8_PORE_SCOM_AND;
+ else
+ // ... do an append (this better be to an _AND register type)
+ operation = P8_PORE_SCOM_APPEND;
+ }
+ else if ( i_operation==P8_PORE_SCOM_OR_APPEND )
+ {
+ if (hostScomEntryMatch)
+ // ... do the OR on existing Scom
+ operation = P8_PORE_SCOM_OR;
+ else
+ // ... do an append (this better be to an _OR register type)
+ operation = P8_PORE_SCOM_APPEND;
+ }
+ else if (i_operation==P8_PORE_SCOM_RESET)
+ {
+ // ... create RNNN instruction sequence.
+ pore_inline_context_create( &ctx, (void*)bufIIS, XIPSIZE_SCOM_ENTRY, 0, 0);
+ pore_RET( &ctx);
+ pore_NOP( &ctx);
+ pore_NOP( &ctx);
+ pore_NOP( &ctx);
+ if (ctx.error > 0) {
+ MY_ERR("***_RET or _NOP generated rc = %d", ctx.error);
+ return IMGBUILD_ERR_PORE_INLINE_ASM;
+ }
+ operation = i_operation;
+ }
+ else
+ {
+ MY_ERR("Scom operation = %i is not within valid range of [%d;%d]\n",
+ i_operation, P8_PORE_SCOM_FIRST_OP, P8_PORE_SCOM_LAST_OP);
+ return IMGBUILD_ERR_SCOM_INVALID_PARM;
+ }
+
+ //----------------------------------------------------------------------------
+ // 4. Check for overrun.
+ //----------------------------------------------------------------------------
+ // Note:
+ // - An entry count exceeding the max allocated entry count will result in a code error
+ // because the allocation is based on an agreed upon max number of entries and
+ // therefore either the code header file needs to change or the caller is not abiding
+ // by the rules.
+ // - An entry count equalling the max allocated entry count is allowed for all commands
+ // except the APPEND command, incl the translated REPLACE->APPEND, which will result
+ // in the previously mentioned code error being returned.
+ // - The table can be full but still include NOOPs. If so, we can still APPEND since
+ // we append at first occurrence of a NOOP or at the end of the table (at the RET).
+ switch (i_section) {
+ case P8_SCOM_SECTION_NC:
+ if ( ( (operation==P8_PORE_SCOM_APPEND && entriesCount==SLW_MAX_SCOMS_NC) &&
+ hostScomEntryNOP==NULL ) ||
+ entriesCount>SLW_MAX_SCOMS_NC )
+ {
+ MY_ERR("SCOM table NC is full. Max %i entries allowed.\n",SLW_MAX_SCOMS_NC);
+ return IMGBUILD_ERR_CHECK_CODE;
+ }
+ break;
+ case P8_SCOM_SECTION_L2:
+ if ( ( (operation==P8_PORE_SCOM_APPEND && entriesCount==SLW_MAX_SCOMS_L2) &&
+ hostScomEntryNOP==NULL ) ||
+ entriesCount>SLW_MAX_SCOMS_L2 )
+ {
+ MY_ERR("SCOM table L2 is full. Max %i entries allowed.\n",SLW_MAX_SCOMS_L2);
+ return IMGBUILD_ERR_CHECK_CODE;
+ }
+ break;
+ case P8_SCOM_SECTION_L3:
+ if ( ( (operation==P8_PORE_SCOM_APPEND && entriesCount==SLW_MAX_SCOMS_L3) &&
+ hostScomEntryNOP==NULL ) ||
+ entriesCount>SLW_MAX_SCOMS_L3 )
+ {
+ MY_ERR("SCOM table L3 is full. Max %i entries allowed.\n",SLW_MAX_SCOMS_L3);
+ return IMGBUILD_ERR_CHECK_CODE;
+ }
+ break;
+ default:
+ MY_ERR("Invalid value for i_section (=%i).\n",i_section);
+ MY_ERR("Valid values for i_section = [%i,%i,%i].\n",
+ P8_SCOM_SECTION_NC,P8_SCOM_SECTION_L2,P8_SCOM_SECTION_L3);
+ return IMGBUILD_ERR_SCOM_INVALID_SUBSECTION;
+ }
+
+
+ // ---------------------------------------------------------------------------
+ // 5. Insert the SCOM.
+ // ---------------------------------------------------------------------------
+ // Assuming pre-allocated Scom table (after pre-allocated Ram table):
+ // - Table is pre-filled with RNNN ISS.
+ // - Each core Id has dedicated space, uniformly distributed by SLW_MAX_SCOMS_NC*
+ // XIPSIZE_SCOM_ENTRY.
+ // - Remember to check for more than SLW_MAX_SCOMS_NC entries!
+ switch (operation) {
+
+ case P8_PORE_SCOM_APPEND: // Append a Scom at first occurring NNNN or RNNN,
+ if (hostScomEntryNOP) {
+ // ... replace the NNNN
+ MY_INF("Append at NOP\n");
+ memcpy(hostScomEntryNOP,(void*)bufIIS,XIPSIZE_SCOM_ENTRY);
+ }
+ else if (hostScomEntryRET) {
+ // ... replace the RNNN
+ MY_INF("Append at RET\n");
+ memcpy(hostScomEntryRET,(void*)bufIIS,XIPSIZE_SCOM_ENTRY);
+ }
+ else {
+ // We should never be here.
+ MY_ERR("In case=_SCOM_APPEND: EntryRET=NULL is impossible. Check code.\n");
+ return IMGBUILD_ERR_CHECK_CODE;
+ }
+ break;
+ case P8_PORE_SCOM_REPLACE: // Replace existing Scom with new data
+ if (hostScomEntryMatch) {
+ // ... do a vanilla replace
+ MY_INF("Replace existing Scom\n");
+ memcpy(hostScomEntryMatch,(void*)bufIIS,XIPSIZE_SCOM_ENTRY);
+ }
+ else {
+ // We should never be here.
+ MY_ERR("In case=_SCOM_REPLACE: EntryMatch=NULL is impossible. Check code.\n");
+ return IMGBUILD_ERR_CHECK_CODE;
+ }
+ break;
+ case P8_PORE_SCOM_NOOP:
+ if (hostScomEntryMatch) {
+ // ... do a vanilla replace
+ MY_INF("Replace existing Scom w/NOPs\n");
+ memcpy(hostScomEntryMatch,(void*)bufIIS,XIPSIZE_SCOM_ENTRY);
+ }
+ else {
+ MY_ERR("No Scom entry found to replace NOOPs with.\n");
+ return IMGBUILD_ERR_SCOM_ENTRY_NOT_FOUND;
+ }
+ break;
+ case P8_PORE_SCOM_OR: // Overlay Scom data onto existing data by bitwise OR
+ if (hostScomEntryMatch) {
+ // ... do an OR on the data (which is the 2nd DWord in the entry)
+ MY_INF("Overlay existing Scom - OR case\n");
+ *((uint64_t*)hostScomEntryMatch+1) =
+ *((uint64_t*)hostScomEntryMatch+1) | myRev64(i_scomData);
+ }
+ else {
+ MY_ERR("No Scom entry found to do OR operation with.\n");
+ return IMGBUILD_ERR_SCOM_ENTRY_NOT_FOUND;
+ }
+ break;
+ case P8_PORE_SCOM_AND: // Overlay Scom data onto existing data by bitwise AND
+ if (hostScomEntryMatch) {
+ // ... do an AND on the data (which is the 2nd DWord in the entry)
+ MY_INF("Overlay existing Scom - AND case\n");
+ *((uint64_t*)hostScomEntryMatch+1) =
+ *((uint64_t*)hostScomEntryMatch+1) & myRev64(i_scomData);
+ }
+ else {
+ MY_ERR("No Scom entry found to do AND operation with.\n");
+ return IMGBUILD_ERR_SCOM_ENTRY_NOT_FOUND;
+ }
+ break;
+ case P8_PORE_SCOM_RESET: // Reset (delete) table. Refill w/RNNN ISS.
+ MY_INF("Reset table\n");
+ hostScomEntryNext = hostScomTableThis;
+ for ( iEntry=0; iEntry<entriesCount; iEntry++) {
+ memcpy( hostScomEntryNext, (void*)bufIIS, XIPSIZE_SCOM_ENTRY);
+ hostScomEntryNext = (void*)((uintptr_t)hostScomEntryNext + XIPSIZE_SCOM_ENTRY);
+ }
+ break;
+ default:
+ MY_ERR("Impossible value of operation (=%i). Check code.\n",operation);
+ return IMGBUILD_ERR_CHECK_CODE;
+
+ } // End of switch(operation)
+
+ return rc;
+}
diff --git a/roms/skiboot/libpore/p8_pore_table_static_data.c b/roms/skiboot/libpore/p8_pore_table_static_data.c
new file mode 100644
index 000000000..d6c35b880
--- /dev/null
+++ b/roms/skiboot/libpore/p8_pore_table_static_data.c
@@ -0,0 +1,62 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/hwpf/hwp/build_winkle_images/p8_slw_build/p8_pore_table_static_data.c $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2012,2014 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+// $Id: p8_pore_table_static_data.c,v 1.7 2013-05-23 21:10:38 dcrowell Exp $
+/*------------------------------------------------------------------------------*/
+/* *! (C) Copyright International Business Machines Corp. 2012 */
+/* *! All Rights Reserved -- Property of IBM */
+/* *! *** *** */
+/*------------------------------------------------------------------------------*/
+/* *! TITLE : p8_pore_table_static_data */
+/* *! DESCRIPTION : Global static data declaration file. */
+/* *! OWNER NAME : Michael Olsen Email: cmolsen@us.ibm.com */
+//
+/* *! COMMENTS : This file is exclusively for PHYP environment. */
+//
+/*------------------------------------------------------------------------------*/
+#include <p8_pore_table_gen_api.H>
+
+const SlwSprRegs SLW_SPR_REGS[] = {
+ /* name value swizzled */
+ // ...core regs
+ { "P8_SPR_HRMOR", P8_SPR_HRMOR, ( P8_SPR_HRMOR >>5 | ( P8_SPR_HRMOR &0x1f)<<5 ) },
+ { "P8_SPR_HMEER", P8_SPR_HMEER, ( P8_SPR_HMEER >>5 | ( P8_SPR_HMEER &0x1f)<<5 ) },
+ { "P8_SPR_PMICR", P8_SPR_PMICR, ( P8_SPR_PMICR >>5 | ( P8_SPR_PMICR &0x1f)<<5 ) },
+ { "P8_SPR_PMCR", P8_SPR_PMCR, ( P8_SPR_PMCR >>5 | ( P8_SPR_PMCR &0x1f)<<5 ) },
+ { "P8_SPR_HID0", P8_SPR_HID0, ( P8_SPR_HID0 >>5 | ( P8_SPR_HID0 &0x1f)<<5 ) },
+ { "P8_SPR_HID1", P8_SPR_HID1, ( P8_SPR_HID1 >>5 | ( P8_SPR_HID1 &0x1f)<<5 ) },
+ { "P8_SPR_HID4", P8_SPR_HID4, ( P8_SPR_HID4 >>5 | ( P8_SPR_HID4 &0x1f)<<5 ) },
+ { "P8_SPR_HID5", P8_SPR_HID5, ( P8_SPR_HID5 >>5 | ( P8_SPR_HID5 &0x1f)<<5 ) },
+ { "P8_CORE_XTRA8", P8_CORE_XTRA8,( P8_CORE_XTRA8 ) },
+ { "P8_CORE_XTRA9", P8_CORE_XTRA9,( P8_CORE_XTRA9 ) },
+ // ...thread regs
+ { "P8_SPR_HSPRG0", P8_SPR_HSPRG0,( P8_SPR_HSPRG0>>5 | ( P8_SPR_HSPRG0&0x1f)<<5 ) },
+ { "P8_SPR_LPCR", P8_SPR_LPCR, ( P8_SPR_LPCR >>5 | ( P8_SPR_LPCR &0x1f)<<5 ) },
+ { "P8_MSR_MSR", P8_MSR_MSR, ( P8_MSR_MSR ) },
+ { "P8_THRD_XTRA3", P8_THRD_XTRA3,( P8_THRD_XTRA3 ) },
+ { "P8_THRD_XTRA4", P8_THRD_XTRA4,( P8_THRD_XTRA4 ) },
+};
+
+const int SLW_SPR_REGS_SIZE = sizeof(SLW_SPR_REGS)/sizeof(SLW_SPR_REGS[0]);
diff --git a/roms/skiboot/libpore/p9_cpu_reg_restore_instruction.H b/roms/skiboot/libpore/p9_cpu_reg_restore_instruction.H
new file mode 100644
index 000000000..cf00ff5e5
--- /dev/null
+++ b/roms/skiboot/libpore/p9_cpu_reg_restore_instruction.H
@@ -0,0 +1,88 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p9/procedures/utils/stopreg/p9_cpu_reg_restore_instruction.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015,2018 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file p9_cpu_reg_restore_instruction.H
+/// @brief enumerates all the opcodes used for SPR restoration.
+///
+// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
+// *HWP Team : PM
+// *HWP Level : 2
+// *HWP Consumed by : HB:HYP
+
+#ifndef __REG_RESTORE_INSTRUCTION_H
+#define __REG_RESTORE_INSTRUCTION_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+
+namespace stopImageSection
+{
+#endif
+
+/**
+ * @brief enumerates opcodes for few instructions.
+ */
+enum
+{
+ ORI_OPCODE = 24,
+ RFI_OPCODE = 19,
+ RFI_CONST = 50,
+ MFMSR_CONST = 83,
+ ORIS_OPCODE = 25,
+ OPCODE_31 = 31,
+ XOR_CONST = 316,
+ RLDICR_OPCODE = 30,
+ RLDICR_CONST = 1,
+ MTSPR_CONST1 = 467,
+ MTMSRD_CONST1 = 178,
+ MFSPR_CONST = 339,
+ OPCODE_18 = 18,
+ SELF_SAVE_FUNC_ADD = 0x2300,
+ SELF_SAVE_OFFSET = 0x180,
+};
+
+#define MR_R0_TO_R10 0x7c0a0378UL //mr r10 r0
+#define MR_R0_TO_R21 0x7c150378UL //mr r21 r0
+#define MR_R0_TO_R9 0x7c090378UL //mr r9 r0
+#define URMOR_CORRECTION 0x7d397ba6UL
+#define BLR_INST 0x4e800020UL
+#define MTSPR_BASE_OPCODE 0x7c0003a6UL
+#define ATTN_OPCODE 0x00000200UL
+#define SKIP_SPR_REST_INST 0x4800001cUL //b . +0x01c
+#define MFLR_R30 0x7fc802a6UL
+#define SKIP_SPR_SELF_SAVE 0x3bff0020UL //addi r31 r31 0x20
+#define MTLR_INST 0x7fc803a6UL //mtlr r30
+
+#ifdef __cplusplus
+} // namespace stopImageSection ends
+
+} // extern "C"
+#endif //__cplusplus
+
+#endif //__REG_RESTORE_INSTRUCTION_H
diff --git a/roms/skiboot/libpore/p9_hcd_header_defs.H b/roms/skiboot/libpore/p9_hcd_header_defs.H
new file mode 100644
index 000000000..49c814a46
--- /dev/null
+++ b/roms/skiboot/libpore/p9_hcd_header_defs.H
@@ -0,0 +1,152 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p9/procedures/hwp/lib/p9_hcd_header_defs.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+///
+/// @file p9_hcd_header_defs.H
+/// @brief defines header constants based on file types
+///
+/// This header contains those cpp manifest constants required for processing
+/// the linker scripts used to generate OCC code images. As these are used
+/// by linker scripts as well as by C++ code, these cannot be solely be put
+/// into a namespace. Prefixing these with the region name is the attempt
+/// to make these globally unique when this header is included in C++ code.
+///
+// *HWP HWP Owner: David Du <daviddu@us.ibm.com>
+// *HWP Backup HWP Owner: Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner: Prem Jha <premjha2@in.ibm.com>
+// *HWP Team: PM
+// *HWP Level: 2
+// *HWP Consumed by: PM
+//
+
+#ifndef __HCD_HEADER_DEFS_H__
+#define __HCD_HEADER_DEFS_H__
+
+/// Macros for generating an Hcode header section
+///
+/// The CPP macros HCD_HDR_UINTxx generate equivalent code depending on
+/// whether they are being called from assembler (where they actually
+/// create the header section data) or from C (where they specifiy a
+/// C-structure form of the contents of the header section.
+///
+/// In assembler each invocation also creates space in the header section
+
+#ifdef __ASSEMBLER__
+
+// *INDENT-OFF*
+ .macro hcd_header_uint64, symbol:req, value = 0
+ .global \symbol
+\symbol\():
+ .quad (\value)
+ .endm
+
+ .macro hcd_header_uint32, symbol:req, value = 0
+ .global \symbol
+ \symbol\():
+ .long (\value)
+ .endm
+
+ .macro hcd_header_uint16, symbol:req, value = 0
+ .global \symbol
+\symbol\():
+ .short (\value)
+ .endm
+
+ .macro hcd_header_uint8, symbol:req, value = 0
+ .global \symbol
+\symbol\():
+ .byte (\value)
+ .endm
+
+ .macro hcd_header_uint8_vec, symbol:req, number:req, value = 0
+ .global \symbol
+\symbol\():
+ .rept (\number)
+ .byte (\value)
+ .endr
+ .endm
+
+ .macro hcd_header_attn, symbol:req, number = 1
+ .global \symbol
+\symbol\():
+ .rept (\number)
+ .long 0x00000200
+ .endr
+ .endm
+
+ .macro hcd_header_attn_pad, align:req
+ .balignl (\align), 0x00000200
+ .endm
+
+ .macro hcd_header_pad, align:req
+ .balignl (\align), 0
+ .endm
+// *INDENT-ON*
+
+#define ULL(x) x
+#define HCD_CONST(name, expr) .set name, expr;
+#define HCD_CONST64(name, expr) .set name, expr;
+
+#define HCD_HDR_UINT64(symbol, value) hcd_header_uint64 symbol value
+#define HCD_HDR_UINT32(symbol, value) hcd_header_uint32 symbol value
+#define HCD_HDR_UINT16(symbol, value) hcd_header_uint16 symbol value
+#define HCD_HDR_UINT8(symbol, value) hcd_header_uint8 symbol value
+#define HCD_HDR_UINT8_VEC(symbol, number, value) hcd_header_uint8_vec symbol number value
+#define HCD_HDR_ATTN(symbol, number) hcd_header_attn symbol number
+#define HCD_HDR_ATTN_PAD(align) hcd_header_attn_pad align
+#define HCD_HDR_PAD(align) hcd_header_pad align
+
+#else // NOT __ASSEMBLER__
+
+#ifdef __LINKERSCRIPT__
+
+ #define ULL(x) x
+ #define POUND_DEFINE #define
+ #define HCD_CONST(name, expr) POUND_DEFINE name expr
+ #define HCD_CONST64(name, expr) POUND_DEFINE name expr
+
+#else
+
+ #define ULL(x) x##ull
+ #define HCD_CONST(name, expr) enum { name = expr };
+ #define HCD_CONST64(name, expr) enum { name = expr };
+
+ #define HCD_HDR_UINT64(symbol, value) uint64_t symbol
+ #define HCD_HDR_UINT32(symbol, value) uint32_t symbol
+ #define HCD_HDR_UINT16(symbol, value) uint16_t symbol
+ #define HCD_HDR_UINT8(symbol, value) uint8_t symbol
+ #define HCD_HDR_UINT8_VEC(symbol, number, value) uint8_t symbol[number]
+ #define HCD_HDR_ATTN(symbol, number) uint32_t symbol[number]
+ #define HCD_HDR_ATTN_PAD(align)
+ #define HCD_HDR_PAD(align)
+
+#endif // __LINKERSCRIPT__
+#endif // __ASSEMBLER__
+
+// Stringification
+
+#define STR_HELPER(x) #x
+#define STR(x) STR_HELPER(x)
+
+#endif // __HCD_HEADER_DEFS_H__
diff --git a/roms/skiboot/libpore/p9_hcd_memmap_base.H b/roms/skiboot/libpore/p9_hcd_memmap_base.H
new file mode 100644
index 000000000..000fafefc
--- /dev/null
+++ b/roms/skiboot/libpore/p9_hcd_memmap_base.H
@@ -0,0 +1,558 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p9/procedures/hwp/lib/p9_hcd_memmap_base.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015,2018 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+///
+/// @file p9_hcd_memmap_base.H
+/// @brief defines region constants shared by different memory components.
+///
+
+// *HWP HWP Owner: David Du <daviddu@us.ibm.com>
+// *HWP Backup HWP Owner: Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner: Prem S Jha <premjha2@in.ibm.com>
+// *HWP Team: PM
+// *HWP Level: 2
+// *HWP Consumed by: PM:Hostboot:Phyp
+
+#ifndef __HCD_MEMMAP_BASE_H__
+#define __HCD_MEMMAP_BASE_H__
+
+#include <p9_hcd_header_defs.H>
+
+// -------------------------------------------------------------------
+// Note: There can be NO semicolons(";") at end of macros in this file
+// There can ONLY have HCD_CONST/HCD_CONST64 macros in this file
+// -------------------------------------------------------------------
+
+/// Image Magic Numbers
+
+HCD_CONST64(CPMR_MAGIC_NUMBER, ULL(0x43504d525f312e30)) // CPMR_1.0
+HCD_CONST64(CME_MAGIC_NUMBER , ULL(0x434d455f5f312e30)) // CME__1.0
+
+HCD_CONST64(QPMR_MAGIC_NUMBER, ULL(0x51504d525f312e30)) // QPMR_1.0
+HCD_CONST64(SGPE_MAGIC_NUMBER, ULL(0x534750455f312e30)) // SGPE_1.0
+
+HCD_CONST64(PPMR_MAGIC_NUMBER, ULL(0x50504d525f312e30)) // PPMR_1.0
+HCD_CONST64(PGPE_MAGIC_NUMBER, ULL(0x504750455F312E30)) // PGPE_1.0
+
+HCD_CONST(CME_BUILD_VERSION, 0x001) // CME__1.0
+HCD_CONST(SGPE_BUILD_VERSION, 0x003) // SGPE_3.0
+HCD_CONST(PGPE_BUILD_VERSION, 0x001) // PGPE_1.0
+
+HCD_CONST64(CPMR_MAGIC_NUMBER_BASE, ULL(0x43504d525f302e30)) // CPMR_0.0
+HCD_CONST(CPMR_REGION_CHECK_WORD, (0x43504d52)) // CPMR
+HCD_CONST64(CME_MAGIC_NUMBER_BASE , ULL(0x434d455f5f302e30)) // CME__0.0
+HCD_CONST64(QPMR_MAGIC_NUMBER_BASE, ULL(0x51504d525f302e30)) // QPMR_0.0
+HCD_CONST64(SGPE_MAGIC_NUMBER_BASE, ULL(0x534750455f302e30)) // SGPE_0.0
+HCD_CONST64(PPMR_MAGIC_NUMBER_BASE, ULL(0x50504d525f302e30)) // PPMR_0.0
+HCD_CONST64(PGPE_MAGIC_NUMBER_BASE, ULL(0x504750455F302E30)) // PGPE_0.0
+
+/// Size constants
+
+HCD_CONST(HALF_KB, 512)
+HCD_CONST(ONE_KB, 1024)
+HCD_CONST(HALF_MB, (1024 * 512))
+HCD_CONST(ONE_MB, (1024 * 1024))
+HCD_CONST(TWO_MB, (2 * 1024 * 1024))
+
+/// Memory constants
+
+HCD_CONST(CME_SRAM_SIZE, (32 * ONE_KB))
+HCD_CONST(OCC_SRAM_SIZE, (768 * ONE_KB))
+
+HCD_CONST(HOMER_MEMORY_SIZE, (4 * ONE_MB))
+HCD_CONST(HOMER_OPMR_REGION_NUM, 0)
+HCD_CONST(HOMER_QPMR_REGION_NUM, 1)
+HCD_CONST(HOMER_CPMR_REGION_NUM, 2)
+HCD_CONST(HOMER_PPMR_REGION_NUM, 3)
+
+/// Chip constants
+
+HCD_CONST(MAX_THREADS_PER_CORE, 4)
+HCD_CONST(MAX_CORES_PER_CHIP, 24)
+
+HCD_CONST(MAX_CMES_PER_CHIP, 12)
+HCD_CONST(MAX_EXES_PER_CHIP, 12)
+
+HCD_CONST(MAX_QUADS_PER_CHIP, 6)
+HCD_CONST(MAX_CACHES_PER_CHIP, 6)
+
+HCD_CONST(MAX_CORES_PER_CME, 2)
+HCD_CONST(MAX_CORES_PER_EX, 2)
+
+HCD_CONST(MAX_CMES_PER_QUAD, 2)
+HCD_CONST(MAX_EXES_PER_QUAD, 2)
+
+HCD_CONST(CACHE0_CHIPLET_ID, 0x10)
+HCD_CONST(CACHE_CHIPLET_ID_MIN, 0x10)
+HCD_CONST(CACHE_CHIPLET_ID_MAX, 0x15)
+
+HCD_CONST(CORE0_CHIPLET_ID, 0x20)
+HCD_CONST(CORE_CHIPLET_ID_MIN, 0x20)
+HCD_CONST(CORE_CHIPLET_ID_MAX, 0x37)
+
+HCD_CONST(MAX_QUAD_ID_SUPPORTED, 5)
+HCD_CONST(MAX_CORE_ID_SUPPORTED, 23)
+HCD_CONST(MAX_THREAD_ID_SUPPORTED, 3)
+
+/// Image build constants
+
+HCD_CONST(HARDWARE_IMG_SIZE, ONE_MB)
+
+HCD_CONST(FUSED_CORE_MODE, 0xBB)
+HCD_CONST(NONFUSED_CORE_MODE, 0xAA)
+
+HCD_CONST(SELF_RESTORE_BLR_INST, 0x4e800020)
+HCD_CONST(CORE_RESTORE_PAD_OPCODE, 0x00000200) //ATTN Opcode
+
+HCD_CONST(SCOM_RESTORE_PAD_OPCODE, 0x00000000) //zero pads
+HCD_CONST(SCOM_RESTORE_ENTRY_SIZE, 16) //4B pad,4B address,8B data
+
+HCD_CONST(CME_BLOCK_READ_LEN, 32)
+HCD_CONST(CME_BLK_SIZE_SHIFT, 0x05)
+
+HCD_CONST(RING_ALIGN_BOUNDARY, 0x08)
+HCD_CONST64(DARN_BAR_EN_POS, ULL(0x8000000000000000))
+
+//---------------------------------------------------------------------------------------
+
+/// OPMR
+
+HCD_CONST(OCC_HOST_AREA_SIZE, ONE_MB)
+HCD_CONST(OPMR_OCC_IMAGE_SIZE, HALF_MB)
+HCD_CONST(OPMR_HOST_AREA_SIZE, HALF_MB)
+
+//---------------------------------------------------------------------------------------
+
+/// QPMR Header
+
+HCD_CONST(QPMR_HOMER_OFFSET, (HOMER_QPMR_REGION_NUM* ONE_MB))
+HCD_CONST(QPMR_HEADER_SIZE, 512)
+
+HCD_CONST(QPMR_MAGIC_NUMBER_BYTE, 0x00)
+HCD_CONST(QPMR_BOOT_COPIER_OFFSET_BYTE, 0x08)
+HCD_CONST(QPMR_BOOT_LOADER_OFFSET_BYTE, 0x10)
+HCD_CONST(QPMR_BOOT_LOADER_LENGTH_BYTE, 0x14)
+HCD_CONST(QPMR_BUILD_DATE_BYTE, 0x18)
+HCD_CONST(QPMR_BUILD_VER_BYTE, 0x1C)
+HCD_CONST(QPMR_SGPE_HCODE_OFFSET_BYTE, 0x28)
+HCD_CONST(QPMR_SGPE_HCODE_LENGTH_BYTE, 0x2C)
+HCD_CONST(QPMR_QUAD_COMMON_RINGS_OFFSET_BYTE, 0x30)
+HCD_CONST(QPMR_QUAD_COMMON_RINGS_LENGTH_BYTE, 0x34)
+HCD_CONST(QPMR_QUAD_OVERRIDE_RINGS_OFFSET_BYTE, 0x38)
+HCD_CONST(QPMR_QUAD_OVERRIDE_RINGS_LENGTH_BYTE, 0x3C)
+HCD_CONST(QPMR_QUAD_SPECIFIC_RINGS_OFFSET_BYTE, 0x40)
+HCD_CONST(QPMR_QUAD_SPECIFIC_RINGS_LENGTH_BYTE, 0x44)
+HCD_CONST(QPMR_QUAD_SCOM_RESTORE_OFFSET_BYTE, 0x48)
+HCD_CONST(QPMR_QUAD_SCOM_RESTORE_LENGTH_BYTE, 0x4C)
+HCD_CONST(QPMR_AUX_DATA_OFFSET_BYTE, 0x50)
+HCD_CONST(QPMR_AUX_DATA_LENGTH_BYTE, 0x54)
+HCD_CONST(QPMR_STOP_FFDC_OFFSET_BYTE, 0x58)
+HCD_CONST(QPMR_STOP_FFDC_LENGTH_BYTE, 0x5C)
+HCD_CONST(QPMR_SGPE_BOOT_PROG_CODE, 0x60)
+HCD_CONST(QPMR_SGPE_IMAGE_SIZE, 0x64)
+HCD_CONST(QPMR_QUAD_MAX_SCOM_ENTRY_BYTE, 0x68)
+
+/// SGPE Boot
+
+HCD_CONST(SGPE_BOOT_COPIER_QPMR_OFFSET, QPMR_HEADER_SIZE)
+HCD_CONST(SGPE_BOOT_COPIER_SIZE, ONE_KB)
+
+HCD_CONST(SGPE_BOOT_LOADER_QPMR_OFFSET,
+ (SGPE_BOOT_COPIER_QPMR_OFFSET + SGPE_BOOT_COPIER_SIZE))
+HCD_CONST(SGPE_BOOT_LOADER_SIZE, ONE_KB)
+HCD_CONST(SGPE_BOOT_LOADER_RESET_ADDR_VAL, 0x40)
+
+HCD_CONST(SGPE_INSTRUMENTATION_SIZE, (2 * ONE_KB))
+
+/// SGPE Image
+
+HCD_CONST(SGPE_IMAGE_QPMR_OFFSET,
+ (SGPE_BOOT_LOADER_QPMR_OFFSET + SGPE_BOOT_LOADER_SIZE))
+HCD_CONST(SGPE_IMAGE_SIZE, (80 * ONE_KB)) //RTC158543
+HCD_CONST(SGPE_INT_VECTOR_SIZE, 384)
+HCD_CONST(SGPE_HCODE_RESET_ADDR_VAL, 0x40)
+
+/// SGPE Header
+
+HCD_CONST(SGPE_HEADER_QPMR_OFFSET,
+ (SGPE_IMAGE_QPMR_OFFSET + SGPE_INT_VECTOR_SIZE))
+HCD_CONST(SGPE_HEADER_IMAGE_OFFSET, SGPE_INT_VECTOR_SIZE)
+HCD_CONST(SGPE_HEADER_SIZE, 128)
+
+HCD_CONST(SGPE_MAGIC_NUMBER_BYTE, 0x00)
+HCD_CONST(SGPE_SYSTEM_RESET_ADDR_BYTE, 0x08)
+HCD_CONST(SGPE_IVPR_ADDR_BYTE, 0x10)
+HCD_CONST(SGPE_BUILD_DATE_BYTE, 0x18)
+HCD_CONST(SGPE_BUILD_VER_BYTE, 0x1C)
+HCD_CONST(SGPE_STOP_FLAGS_BYTE, 0x20)
+HCD_CONST(SGPE_LOCATION_ID_BYTE, 0x24)
+HCD_CONST(SGPE_QUAD_COMMON_RING_SRAM_OFF_BYTE, 0x28)
+HCD_CONST(SGPE_QUAD_OVERRIDE_RING_SRAM_OFF_BYTE, 0x2C)
+HCD_CONST(SGPE_QUAD_SPECIFIC_RING_SRAM_OFF_BYTE, 0x30)
+HCD_CONST(SGPE_QUAD_SCOM_RESTORE_SRAM_OFF_BYTE, 0x34)
+HCD_CONST(SGPE_QUAD_SCOM_RESTORE_MEM_OFF_BYTE, 0x38)
+HCD_CONST(SGPE_QUAD_SCOM_RESTORE_LENGTH_BYTE, 0x3C)
+HCD_CONST(SGPE_AUX_DATA_OFFSET_BYTE, 0x40)
+HCD_CONST(SGPE_AUX_DATA_LENGTH_BYTE, 0x44)
+HCD_CONST(SGPE_AUX_CTRL_BYTE, 0x48)
+HCD_CONST(SGPE_CHTM_MEM_CFG_BYTE, 0x50)
+
+HCD_CONST(SGPE_RESET_ADDR_IMAGE_OFFSET, (SGPE_HEADER_IMAGE_OFFSET + SGPE_SYSTEM_RESET_ADDR_BYTE))
+HCD_CONST(SGPE_BUILD_DATE_IMAGE_OFFSET, (SGPE_HEADER_IMAGE_OFFSET + SGPE_BUILD_DATE_BYTE))
+HCD_CONST(SGPE_BUILD_VER_IMAGE_OFFSET, (SGPE_HEADER_IMAGE_OFFSET + SGPE_BUILD_VER_BYTE))
+
+HCD_CONST(SGPE_STOP_4_TO_2_BIT_POS, 0x80000000)
+HCD_CONST(SGPE_STOP_5_TO_4_BIT_POS, 0x40000000)
+HCD_CONST(SGPE_STOP_8_TO_5_BIT_POS, 0x20000000)
+HCD_CONST(SGPE_STOP_11_TO_8_BIT_POS, 0x10000000)
+HCD_CONST(SGPE_ENABLE_CME_TRACE_ARRAY_BIT_POS, 0x08000000)
+HCD_CONST(SGPE_VDM_ENABLE_BIT_POS, 0x04000000)
+HCD_CONST(SGPE_ENABLE_CHTM_TRACE_CME_BIT_POS, 0x02000000)
+HCD_CONST(SGPE_PROC_FAB_PUMP_MODE_BIT_POS, 0x00004000)
+HCD_CONST(SGPE_CACHE_SKEWADJ_DISABLE_BIT_POS, 0x00002000)
+HCD_CONST(SGPE_CACHE_DCADJ_DISABLE_BIT_POS, 0x00001000)
+
+///24x7
+HCD_CONST(QPMR_AUX_OFFSET, (512 * ONE_KB))
+HCD_CONST(QPMR_AUX_LENGTH, (64 * ONE_KB))
+/// SGPE Hcode
+
+HCD_CONST(SGPE_HCODE_IMAGE_OFFSET, (SGPE_INT_VECTOR_SIZE + SGPE_HEADER_SIZE))
+HCD_CONST(SGPE_HCODE_SIZE, ((45 * ONE_KB) + HALF_KB)) //RTC158543
+HCD_CONST(SGPE_DEBUG_PTRS_OFFSET, 0x200)
+HCD_CONST(SGPE_DEBUG_PTRS_SIZE, 0x24)
+HCD_CONST(SGPE_DBG_PTR_AREA_SIZE, 64)
+
+/// Quad Scan
+
+// 400B * 9 rings * 3 types (base, RL, CC)
+HCD_CONST(QUAD_COMMON_RING_SIZE, (13 * ONE_KB))
+// 300B * 9 rings
+HCD_CONST(QUAD_OVERRIDE_RING_SIZE, (3 * ONE_KB))
+// 1KB/ring * 5 rings/cache
+HCD_CONST(QUAD_SPECIFIC_RING_SIZE_PER_QUAD, ((3 * ONE_KB) + HALF_KB))
+HCD_CONST(QUAD_SPECIFIC_RING_SIZE_TOTAL, (19 * ONE_KB)) //checkme?
+
+/// Quad Scom
+
+HCD_CONST(QUAD_SCOM_RESTORE_QPMR_OFFSET, (128 * ONE_KB))
+HCD_CONST(QUAD_SCOM_RESTORE_HOMER_OFFSET,
+ (QUAD_SCOM_RESTORE_QPMR_OFFSET + QPMR_HOMER_OFFSET))
+
+HCD_CONST(MAX_L2_SCOM_ENTRIES, 16)
+HCD_CONST(MAX_L3_SCOM_ENTRIES, 16)
+
+//HW423686
+//Inorder to continue IMA after STOP11 on all four cores of a quad, 2
+//EQ SCOM registers need to restored per core. STOP API desgin allowed
+//only 15 SCOM restore entries per EQ. Out of total budget, 12 are
+//consumed during IPL. Hence it was not possible to manage IMA within
+//this limit. As a resolution, limit for EQ SCOM restore entries has
+//been changed to 31. Below is the break down for EQ SCOM Restore
+//Entries
+
+// Power Management 12
+// Core IMA 08
+// PRD FIR Mask 05
+// Reserve 06
+
+HCD_CONST(MAX_EQ_SCOM_ENTRIES, 31)
+HCD_CONST(QUAD_SCOM_RESTORE_REGS_PER_QUAD, 256)
+
+HCD_CONST(QUAD_SCOM_RESTORE_SIZE_PER_QUAD,
+ (SCOM_RESTORE_ENTRY_SIZE* QUAD_SCOM_RESTORE_REGS_PER_QUAD))
+
+HCD_CONST(QUAD_SCOM_RESTORE_SIZE_TOTAL, (6 * ONE_KB)) //rounded to 6KB
+HCD_CONST(LEGACY_SCOM_RESTORE_VER, 0x02)
+//---------------------------------------------------------------------------------------
+
+/// CPMR Header
+
+HCD_CONST(CPMR_HOMER_OFFSET, (HOMER_CPMR_REGION_NUM* ONE_MB))
+HCD_CONST(CPMR_HEADER_SIZE, 256)
+
+HCD_CONST(CPMR_ATTN_WORD0_BYTE, 0x00)
+HCD_CONST(CPMR_ATTN_WORD1_BYTE, 0x04)
+HCD_CONST(CPMR_MAGIC_NUMBER_BYTE, 0x08)
+HCD_CONST(CPMR_BUILD_DATE_BYTE, 0x10)
+HCD_CONST(CPMR_BUILD_VER_BYTE, 0x14)
+HCD_CONST(CPMR_SELF_RESTORE_VER_BYTE, 0x1C)
+HCD_CONST(CPMR_STOP_API_VER_BYTE, 0x1D)
+HCD_CONST(CPMR_URMOR_FIX_BYTE, 0x1E)
+HCD_CONST(CPMR_CME_HCODE_OFFSET_BYTE, 0x20)
+HCD_CONST(CPMR_CME_HCODE_LENGTH_BYTE, 0x24)
+HCD_CONST(CPMR_CORE_COMMON_RING_OFFSET_BYTE, 0x28)
+HCD_CONST(CPMR_CORE_COMMON_RING_LENGTH_BYTE, 0x2C)
+HCD_CONST(CPMR_CME_LOCAL_PSTATE_OFFSET_BYTE, 0x30)
+HCD_CONST(CPMR_CME_LOCAL_PSTATE_LENGTH_BYTE, 0x34)
+HCD_CONST(CPMR_CORE_SPECIFIC_RING_OFFSET_BYTE, 0x38)
+HCD_CONST(CPMR_CORE_SPECIFIC_RING_LENGTH_BYTE, 0x3C)
+HCD_CONST(CPMR_CORE_SCOM_RESTORE_OFFSET_BYTE, 0x40)
+HCD_CONST(CPMR_CORE_SCOM_RESTORE_LENGTH_BYTE, 0x44)
+HCD_CONST(CPMR_SELF_RESTORE_OFFSET_BYTE, 0x48)
+HCD_CONST(CPMR_SELF_RESTORE_LENGTH_BYTE, 0x4C)
+HCD_CONST(CPMR_MAX_SCOM_REST_PER_CORE_BYTE, 0x50)
+
+/// Self Restore without SMF Support
+
+HCD_CONST(SELF_RESTORE_CPMR_OFFSET, CPMR_HEADER_SIZE)
+HCD_CONST(SELF_RESTORE_INT_SIZE, (8 * ONE_KB))
+HCD_CONST(THREAD_LAUNCHER_SIZE, 256)
+HCD_CONST(SELF_RESTORE_CODE_SIZE,
+ (SELF_RESTORE_INT_SIZE + THREAD_LAUNCHER_SIZE))
+
+HCD_CONST(CORE_RESTORE_THREAD_AREA_SIZE, (ONE_KB))
+HCD_CONST(CORE_RESTORE_CORE_AREA_SIZE, (ONE_KB))
+HCD_CONST(CORE_RESTORE_SIZE_PER_THREAD,
+ (CORE_RESTORE_THREAD_AREA_SIZE + CORE_RESTORE_CORE_AREA_SIZE))
+HCD_CONST(SELF_RESTORE_CORE_REGS_SIZE,
+ (CORE_RESTORE_SIZE_PER_THREAD*
+ MAX_THREADS_PER_CORE* MAX_CORES_PER_CHIP))
+
+HCD_CONST(SELF_RESTORE_SIZE_TOTAL,
+ (SELF_RESTORE_CODE_SIZE + SELF_RESTORE_CORE_REGS_SIZE))
+
+// Self Restore Region With SMF Support
+HCD_CONST(SMF_THREAD_LAUNCHER_SIZE, 1024)
+HCD_CONST(SMF_SELF_RESTORE_CODE_SIZE,
+ (SELF_RESTORE_INT_SIZE + SMF_THREAD_LAUNCHER_SIZE))
+
+HCD_CONST(SMF_CORE_RESTORE_THREAD_AREA_SIZE, HALF_KB)
+HCD_CONST(SMF_SELF_SAVE_THREAD_AREA_SIZE, 256)
+HCD_CONST(SMF_CORE_RESTORE_CORE_AREA_SIZE, HALF_KB)
+HCD_CONST(SMF_CORE_SAVE_CORE_AREA_SIZE, HALF_KB)
+
+HCD_CONST(SMF_SELF_RESTORE_CORE_REGS_SIZE,
+ MAX_CORES_PER_CHIP * ((SMF_CORE_RESTORE_THREAD_AREA_SIZE* MAX_THREADS_PER_CORE ) +
+ (SMF_SELF_SAVE_THREAD_AREA_SIZE* MAX_THREADS_PER_CORE ) +
+ SMF_CORE_RESTORE_CORE_AREA_SIZE +
+ SMF_CORE_SAVE_CORE_AREA_SIZE ))
+
+HCD_CONST(SMF_SELF_RESTORE_SIZE_TOTAL,
+ (SMF_SELF_RESTORE_CODE_SIZE + SMF_SELF_RESTORE_CORE_REGS_SIZE))
+HCD_CONST( EC_LEVEL_URMOR_FIX, 0x23 )
+/// Core Scom
+
+HCD_CONST(CORE_SCOM_RESTORE_CPMR_OFFSET, (256 * ONE_KB))
+HCD_CONST(CORE_SCOM_RESTORE_HOMER_OFFSET,
+ (CORE_SCOM_RESTORE_CPMR_OFFSET + CPMR_HOMER_OFFSET))
+
+HCD_CONST(MAX_CORE_SCOM_ENTRIES, 15)
+HCD_CONST(CORE_SCOM_RESTORE_REGS_PER_CORE, (MAX_CORE_SCOM_ENTRIES + 1))
+
+HCD_CONST(CORE_SCOM_RESTORE_SIZE_PER_CORE,
+ (SCOM_RESTORE_ENTRY_SIZE* CORE_SCOM_RESTORE_REGS_PER_CORE)) // 16*16=256
+HCD_CONST(CORE_SCOM_RESTORE_SIZE_PER_CME,
+ (CORE_SCOM_RESTORE_SIZE_PER_CORE* MAX_CORES_PER_CME)) // 256*2=512
+
+HCD_CONST(CORE_SCOM_RESTORE_SIZE_TOTAL,
+ (CORE_SCOM_RESTORE_SIZE_PER_CME* MAX_CMES_PER_CHIP)) // 512*12=6K
+
+/// CME Image
+
+HCD_CONST(CME_IMAGE_CPMR_OFFSET,
+ (CORE_SCOM_RESTORE_CPMR_OFFSET + CORE_SCOM_RESTORE_SIZE_TOTAL))
+//HCD_CONST(CME_IMAGE_SIZE, 0)
+HCD_CONST(CME_INT_VECTOR_SIZE, 384)
+
+/// CME Header
+
+HCD_CONST(CME_HEADER_CPMR_OFFSET,
+ (CME_IMAGE_CPMR_OFFSET + CME_INT_VECTOR_SIZE))
+HCD_CONST(CME_HEADER_IMAGE_OFFSET, CME_INT_VECTOR_SIZE)
+HCD_CONST(CME_HEADER_SIZE, 128)
+
+HCD_CONST(CME_MAGIC_NUMBER_BYTE, 0x00)
+HCD_CONST(CME_HCODE_OFFSET_BYTE, 0x08)
+HCD_CONST(CME_HCODE_LENGTH_BYTE, 0x0C)
+HCD_CONST(CME_CORE_COMMON_RING_OFFSET_BYTE, 0x10)
+HCD_CONST(CME_CORE_OVERRIDE_RING_OFFSET_BYTE, 0x14)
+HCD_CONST(CME_CORE_COMMON_RING_LENGTH_BYTE, 0x18)
+HCD_CONST(CME_LOCAL_PSTATE_OFFSET_BYTE, 0x1C)
+HCD_CONST(CME_LOCAL_PSTATE_LENGTH_BYTE, 0x20)
+HCD_CONST(CME_CORE_SPECIFIC_RING_OFFSET_BYTE, 0x24)
+HCD_CONST(CME_CORE_SPECIFIC_RING_LENGTH_BYTE, 0x28)
+HCD_CONST(CME_CORE_SCOM_RESTORE_OFFSET_BYTE, 0x2C)
+HCD_CONST(CME_CORE_SCOM_RESTORE_LENGTH_BYTE, 0x30)
+HCD_CONST(CME_STOP_FLAGS_BYTE, 0x34)
+HCD_CONST(CME_LOCATION_ID_BYTE, 0x38)
+HCD_CONST(CME_QM_FLAGS_BYTE, 0x3A)
+HCD_CONST(CME_HOMER_ADDRESS_BYTE, 0x40)
+
+HCD_CONST(CME_HCODE_OFF_IMAGE_OFFSET, (CME_HEADER_IMAGE_OFFSET + CME_HCODE_OFFSET_BYTE))
+HCD_CONST(CME_HCODE_LEN_IMAGE_OFFSET, (CME_HEADER_IMAGE_OFFSET + CME_HCODE_LENGTH_BYTE))
+
+HCD_CONST(CME_STOP_3_TO_2_BIT_POS, 0x80000000)
+HCD_CONST(CME_STOP_4_TO_2_BIT_POS, 0x40000000)
+HCD_CONST(CME_STOP_5_TO_4_BIT_POS, 0x20000000)
+HCD_CONST(CME_STOP_8_TO_5_BIT_POS, 0x10000000)
+HCD_CONST(CME_STOP_11_TO_8_BIT_POS, 0x08000000)
+HCD_CONST(CME_VDM_ENABLE_BIT_POS, 0x04000000)
+HCD_CONST(CME_STOP_MAPPING_DISABLE_BIT_POS, 0x00000004)
+HCD_CONST(CME_QUEUED_SCAN_DISABLE_BIT_POS, 0x00000002)
+HCD_CONST(CME_SKIP_CORE_POWEROFF_BIT_POS, 0x00000001)
+HCD_CONST(CME_QM_FLAG_RESCLK_ENABLE, 0x8000)
+HCD_CONST(CME_QM_FLAG_SYS_IVRM_ENABLE, 0x4000)
+HCD_CONST(CME_QM_FLAG_SYS_VDM_ENABLE, 0x2000)
+HCD_CONST(CME_QM_FLAG_SYS_WOF_ENABLE, 0x1000)
+HCD_CONST(CME_QM_FLAG_SYS_DYN_FMIN_ENABLE, 0x0800)
+HCD_CONST(CME_QM_FLAG_SYS_DYN_FMAX_ENABLE, 0x0400)
+HCD_CONST(CME_QM_FLAG_SYS_JUMP_PROTECT, 0x0200)
+
+/// CME Hcode
+
+HCD_CONST(CME_HCODE_IMAGE_OFFSET, (CME_INT_VECTOR_SIZE + CME_HEADER_SIZE))
+//HCD_CONST(CME_HCODE_SIZE, 0)
+HCD_CONST(CME_DEBUG_PTRS_OFFSET, 0x200)
+HCD_CONST(CME_DEBUG_PTRS_SIZE, 0x24)
+HCD_CONST(CME_INSTRUMENTATION_SIZE, HALF_KB)
+HCD_CONST(CME_SRAM_HCODE_OFFSET, 0)
+
+/// Core Scan
+
+HCD_CONST(CORE_COMMON_RING_SIZE, (2 * ONE_KB))
+HCD_CONST(CORE_OVERRIDE_RING_SIZE, (1 * ONE_KB))
+HCD_CONST(CORE_SPECIFIC_RING_SIZE_PER_CORE, (1 * ONE_KB))
+HCD_CONST(CORE_SPECIFIC_RING_SIZE_TOTAL, (32 * ONE_KB)) // rounded to 32K
+
+/// Quad P-State
+
+HCD_CONST(CME_QUAD_PSTATE_SIZE, HALF_KB)
+
+// CME Hcode + Core Scan + Pstate
+
+HCD_CONST(CME_REGION_SIZE, (64 * ONE_KB))
+
+// Debug
+
+HCD_CONST(CPMR_TRACE_REGION_OFFSET, (512 * ONE_KB))
+HCD_CONST(CME_TRACE_REGION_SIZE, (16 * ONE_KB))
+HCD_CONST(CPMR_TRACE_REGION_SIZE, (CME_TRACE_REGION_SIZE* MAX_CMES_PER_CHIP)) // 192K
+HCD_CONST(CPMR_DEBUG_REGION_OFFSET, CPMR_TRACE_REGION_OFFSET + CPMR_TRACE_REGION_SIZE)
+HCD_CONST(CPMR_DEBUG_REGION_SIZE, (64 * ONE_KB)) // 192K + 64K = 256K
+
+
+//---------------------------------------------------------------------------------------
+
+/// PPMR Header
+
+HCD_CONST(PPMR_HOMER_OFFSET, (HOMER_PPMR_REGION_NUM* ONE_MB))
+HCD_CONST(PPMR_HEADER_SIZE, 512)
+
+HCD_CONST(PPMR_MAGIC_NUMBER_BYTE, 0x00)
+HCD_CONST(PPMR_BOOT_COPIER_OFFSET_BYTE, 0x08)
+HCD_CONST(PPMR_BOOT_LOADER_OFFSET_BYTE, 0x10)
+HCD_CONST(PPMR_BOOT_LOADER_LENGTH_BYTE, 0x14)
+HCD_CONST(PPMR_BUILD_DATE_BYTE, 0x18)
+HCD_CONST(PPMR_BUILD_VER_BYTE, 0x1C)
+HCD_CONST(PPMR_PGPE_HCODE_OFFSET_BYTE, 0x28)
+HCD_CONST(PPMR_PGPE_HCODE_LENGTH_BYTE, 0x2C)
+HCD_CONST(PPMR_GLOBAL_PSTATE_OFFSET_BYTE, 0x30)
+HCD_CONST(PPMR_GLOBAL_PSTATE_LENGTH_BYTE, 0x34)
+HCD_CONST(PPMR_LOCAL_PSTATE_OFFSET_BYTE, 0x38)
+HCD_CONST(PPMR_LOCAL_PSTATE_LENGTH_BYTE, 0x3C)
+HCD_CONST(PPMR_OCC_PSTATE_OFFSET_BYTE, 0x40)
+HCD_CONST(PPMR_OCC_PSTATE_LENGTH_BYTE, 0x44)
+HCD_CONST(PPMR_PSTATE_TABLE_OFFSET_BYTE, 0x48)
+HCD_CONST(PPMR_PSTATE_TABLE_LENGTH_BYTE, 0x4C)
+HCD_CONST(PPMR_PGPE_SRAM_IMAGE_SIZE_BYTE, 0x50)
+HCD_CONST(PPMR_PGPE_BOOT_PROG_CODE_BYTE, 0x54)
+
+/// PGPE Boot
+
+HCD_CONST(PGPE_BOOT_COPIER_PPMR_OFFSET, PPMR_HEADER_SIZE)
+HCD_CONST(PGPE_BOOT_COPIER_SIZE, ONE_KB)
+
+HCD_CONST(PGPE_BOOT_LOADER_PPMR_OFFSET,
+ (PGPE_BOOT_COPIER_PPMR_OFFSET + PGPE_BOOT_COPIER_SIZE))
+HCD_CONST(PGPE_BOOT_LOADER_SIZE, ONE_KB)
+HCD_CONST(PGPE_BOOT_LOADER_RESET_ADDR_VAL, 0x40)
+
+HCD_CONST(PGPE_INSTRUMENTATION_SIZE, (2 * ONE_KB))
+
+/// PGPE Image
+
+HCD_CONST(PGPE_AUX_TASK_SIZE, (2 * ONE_KB))
+HCD_CONST(PGPE_IMAGE_PPMR_OFFSET,
+ (PGPE_BOOT_LOADER_PPMR_OFFSET + PGPE_BOOT_LOADER_SIZE))
+HCD_CONST(PGPE_IMAGE_SIZE, (48 * ONE_KB)) //RTC158543
+HCD_CONST(PGPE_INT_VECTOR_SIZE, 384)
+HCD_CONST(PGPE_HCODE_RESET_ADDR_VAL, 0x40)
+
+/// PGPE Header
+
+HCD_CONST(PGPE_HEADER_IMAGE_OFFSET, PGPE_INT_VECTOR_SIZE)
+HCD_CONST(PGPE_HEADER_PPMR_OFFSET,
+ (PGPE_IMAGE_PPMR_OFFSET + PGPE_INT_VECTOR_SIZE))
+HCD_CONST(PGPE_HEADER_SIZE, 128)
+
+HCD_CONST(PGPE_MAGIC_NUMBER_BYTE, 0x00)
+HCD_CONST(PGPE_SYSTEM_RESET_ADDR_BYTE, 0x08)
+HCD_CONST(PGPE_SHARED_SRAM_ADDR_BYTE, 0x0C)
+HCD_CONST(PGPE_IVPR_ADDR_BYTE, 0x10)
+HCD_CONST(PGPE_SHARED_SRAM_LENGTH_BYTE, 0x14)
+HCD_CONST(PGPE_BUILD_DATE_BYTE, 0x18)
+HCD_CONST(PGPE_BUILD_VER_BYTE, 0x1C)
+HCD_CONST(PGPE_PGPE_FLAGS_BYTE, 0x20)
+HCD_CONST(PGPE_GLOBAL_PSTATE_SRAM_ADDR_BYTE, 0x28)
+HCD_CONST(PGPE_GLOBAL_PSTATE_MEM_OFFSET_BYTE, 0x30)
+HCD_CONST(PGPE_GLOBAL_PSTATE_PPB_SIZE_BYTE, 0x34)
+HCD_CONST(PGPE_GEN_PSTATE_TABLE_MEM_OFFSET_BYTE, 0x38)
+HCD_CONST(PGPE_GEN_PSTATE_TABLE_SIZE_BYTE, 0x3C)
+HCD_CONST(PGPE_OCC_PSTATE_TABLE_MEM_OFFSET_BYTE, 0x40)
+HCD_CONST(PGPE_OCC_PSTATE_TABLE_SIZE_BYTE, 0x44)
+HCD_CONST(PGPE_BEACON_ADDR_BYTE, 0x48)
+HCD_CONST(PGPE_ACTUAL_QUAD_STATUS_ADDR_BYTE, 0x4C)
+HCD_CONST(PGPE_WOF_TABLE_ADDR_BYTE, 0x50)
+HCD_CONST(PGPE_WOF_TABLE_LENGTH_BYTE, 0x54)
+
+HCD_CONST(PGPE_RESET_ADDR_IMAGE_OFFSET, (PGPE_HEADER_IMAGE_OFFSET + PGPE_SYSTEM_RESET_ADDR_BYTE))
+HCD_CONST(PGPE_BUILD_DATE_IMAGE_OFFSET, (PGPE_HEADER_IMAGE_OFFSET + PGPE_BUILD_DATE_BYTE))
+HCD_CONST(PGPE_BUILD_VER_IMAGE_OFFSET, (PGPE_HEADER_IMAGE_OFFSET + PGPE_BUILD_VER_BYTE))
+
+/// PGPE Hcode
+
+//HCD_CONST(PGPE_HCODE_SIZE, (32 * ONE_KB)) //RTC158543
+HCD_CONST(PGPE_DBG_PTR_AREA_SIZE, 64)
+HCD_CONST(PGPE_GLOBAL_PSTATE_PARAM_BLOCK_SIZE, (4 * ONE_KB))
+
+/// Pstate Parameter Block + Pstate Table
+
+HCD_CONST(OCC_PSTATE_PARAM_BLOCK_PPMR_OFFSET, (128 * ONE_KB))
+HCD_CONST(OCC_PSTATE_PARAM_BLOCK_SIZE, (8 * ONE_KB))
+HCD_CONST(OCC_PSTATE_PARAM_BLOCK_REGION_SIZE, (16 * ONE_KB))
+
+HCD_CONST(PGPE_PSTATE_OUTPUT_TABLES_PPMR_OFFSET, (144 * ONE_KB))
+HCD_CONST(PGPE_PSTATE_OUTPUT_TABLES_SIZE, (8 * ONE_KB))
+HCD_CONST(PGPE_PSTATE_OUTPUT_TABLES_REGION_SIZE, (16 * ONE_KB))
+
+HCD_CONST(OCC_WOF_TABLES_PPMR_OFFSET, (768 * ONE_KB))
+HCD_CONST(OCC_WOF_TABLES_SIZE, (256 * ONE_KB))
+
+HCD_CONST(WOF_TABLE_RESERVE,
+ OCC_WOF_TABLES_PPMR_OFFSET - (PGPE_PSTATE_OUTPUT_TABLES_PPMR_OFFSET + PGPE_PSTATE_OUTPUT_TABLES_REGION_SIZE))
+HCD_CONST(PGPE_IMAGE_RESERVE_SIZE,
+ (OCC_PSTATE_PARAM_BLOCK_PPMR_OFFSET - PGPE_IMAGE_PPMR_OFFSET - PGPE_IMAGE_SIZE - PGPE_AUX_TASK_SIZE))
+
+#endif /* __HCD_MEMMAP_BASE_H__ */
diff --git a/roms/skiboot/libpore/p9_stop_api.C b/roms/skiboot/libpore/p9_stop_api.C
new file mode 100644
index 000000000..33aaf788d
--- /dev/null
+++ b/roms/skiboot/libpore/p9_stop_api.C
@@ -0,0 +1,1743 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p9/procedures/utils/stopreg/p9_stop_api.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015,2018 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file p9_stop_api.C
+/// @brief implements STOP API which create/manipulate STOP image.
+///
+// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
+// *HWP Team : PM
+// *HWP Level : 2
+// *HWP Consumed by : HB:HYP
+
+// *INDENT-OFF*
+#ifdef PPC_HYP
+ #include <HvPlicModule.H>
+#endif
+
+#include "p9_stop_api.H"
+#include "p9_cpu_reg_restore_instruction.H"
+#include "p9_stop_data_struct.H"
+#include <string.h>
+#include "p9_stop_util.H"
+#ifdef __cplusplus
+extern "C" {
+
+namespace stopImageSection
+{
+#endif
+// a true in the table below means register is of scope thread
+// whereas a false meanse register is of scope core.
+
+const StopSprReg_t g_sprRegister[] =
+{
+ { P9_STOP_SPR_CIABR, true, 0 },
+ { P9_STOP_SPR_DAWR, true, 1 },
+ { P9_STOP_SPR_DAWRX, true, 2 },
+ { P9_STOP_SPR_HSPRG0, true, 3 },
+ { P9_STOP_SPR_LDBAR, true, 4, },
+ { P9_STOP_SPR_LPCR, true, 5 },
+ { P9_STOP_SPR_PSSCR, true, 6 },
+ { P9_STOP_SPR_MSR, true, 7 },
+ { P9_STOP_SPR_HRMOR, false, 20 },
+ { P9_STOP_SPR_HID, false, 21 },
+ { P9_STOP_SPR_HMEER, false, 22 },
+ { P9_STOP_SPR_PMCR, false, 23 },
+ { P9_STOP_SPR_PTCR, false, 24 },
+ { P9_STOP_SPR_SMFCTRL, true, 28 },
+ { P9_STOP_SPR_USPRG0, true, 29 },
+ { P9_STOP_SPR_USPRG1, true, 30 },
+ { P9_STOP_SPR_URMOR, false, 31 },
+};
+
+const uint32_t MAX_SPR_SUPPORTED = 17;
+const uint32_t LEGACY_CORE_SCOM_SUPPORTED = 15;
+const uint32_t LEGACY_QUAD_SCOM_SUPPORTED = 63;
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief vaildated input arguments passed to p9_stop_save_cpureg_control.
+ * @param[in] i_pImage point to start of HOMER
+ * @param[in] i_coreId id of the core
+ * @param[in] i_threadId id of the thread
+ * @param[in] i_saveMaskVector SPR save bit mask vector
+ * @return STOP_SAVE_SUCCESS if function succeeds, error code otherwise.
+ */
+STATIC StopReturnCode_t validateArgumentSaveRegMask( void* const i_pImage,
+ uint32_t const i_coreId,
+ uint32_t const i_threadId,
+ uint64_t i_saveMaskVector )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+
+ do
+ {
+ if( !i_pImage )
+ {
+ l_rc = STOP_SAVE_ARG_INVALID_IMG;
+ break;
+ }
+
+ if( i_coreId > MAX_CORE_ID_SUPPORTED )
+ {
+ l_rc = STOP_SAVE_ARG_INVALID_CORE;
+ break;
+ }
+
+ if( i_threadId > MAX_THREAD_ID_SUPPORTED )
+ {
+ l_rc = STOP_SAVE_ARG_INVALID_THREAD;
+ break;
+ }
+
+ if( ( 0 == i_saveMaskVector ) || ( BAD_SAVE_MASK & i_saveMaskVector ) )
+ {
+ l_rc = STOP_SAVE_ARG_INVALID_REG;
+ break;
+ }
+
+ }
+ while(0);
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief validates input arguments provided by STOP API caller.
+ * @param[in] i_pImage pointer to beginning of chip's HOMER image.
+ * @param[in] i_regId SPR register id
+ * @param[in] i_coreId core id
+ * @param[in|out] i_pThreadId points to thread id
+ * @param[in|out] i_pThreadLevelReg points to scope information of SPR
+ * @return STOP_SAVE_SUCCESS if arguments found valid, error code otherwise.
+ * @note for register of scope core, function shall force io_threadId to
+ * zero.
+ */
+STATIC StopReturnCode_t validateSprImageInputs( void* const i_pImage,
+ const CpuReg_t i_regId,
+ const uint32_t i_coreId,
+ uint32_t* i_pThreadId,
+ bool* i_pThreadLevelReg )
+{
+ uint32_t index = 0;
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ bool sprSupported = false;
+ *i_pThreadLevelReg = false;
+
+ do
+ {
+ if( NULL == i_pImage )
+ {
+ // Error: HOMER image start location is not valid
+ // Cannot proceed further. So, let us exit.
+ l_rc = STOP_SAVE_ARG_INVALID_IMG;
+ MY_ERR( "invalid image location " );
+
+ break;
+ }
+
+ // STOP API manages STOP image based on physical core Id. PIR value
+ // is interpreted to calculate the physical core number and virtual
+ // thread number.
+ if( MAX_CORE_ID_SUPPORTED < i_coreId )
+ {
+ // Error: invalid core number. given core number exceeds maximum
+ // cores supported by chip.
+
+ // Physical core number is calculated based on following formula:
+ // core id = 4 * quad id (0..5) + core no within quad ( 0..3)
+ l_rc = STOP_SAVE_ARG_INVALID_CORE;
+ MY_ERR( "invalid core id " );
+ break;
+ }
+
+ if( MAX_THREAD_ID_SUPPORTED < *i_pThreadId )
+ {
+ //Error: invalid core thread. Given core thread exceeds maximum
+ //threads supported in a core.
+
+ // 64 bit PIR value is interpreted to calculate virtual thread
+ // Id. In fuse mode, b61 and b62 gives virtual thread id whereas in
+ // non fuse mode, b62 and b63 is read to determine the same.
+
+ l_rc = STOP_SAVE_ARG_INVALID_THREAD;
+ MY_ERR( "invalid thread " );
+ break;
+ }
+
+ for( index = 0; index < MAX_SPR_SUPPORTED; ++index )
+ {
+ if( i_regId == (CpuReg_t )g_sprRegister[index].iv_sprId )
+ {
+ // given register is in the list of register supported
+ sprSupported = true;
+ *i_pThreadLevelReg = g_sprRegister[index].iv_isThreadScope;
+ *i_pThreadId = *i_pThreadLevelReg ? *i_pThreadId : 0;
+ break;
+ }
+ }
+
+ if( !sprSupported )
+ {
+ // Following SPRs are supported
+ // trace out all registers supported
+ MY_ERR("Register not supported" );
+ // error code to caller.
+ l_rc = STOP_SAVE_ARG_INVALID_REG;
+ break;
+ }
+
+ }
+ while(0);
+
+ if( l_rc )
+ {
+ MY_ERR( "image 0x%08x, regId %08d, coreId %d, "
+ "threadId %d return code 0x%08x", i_pImage, i_regId,
+ i_coreId, *i_pThreadId, l_rc );
+ }
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates ori instruction code.
+ * @param[in] i_Rs Source register number
+ * @param[in] i_Ra destination register number
+ * @param[in] i_data 16 bit immediate data
+ * @return returns 32 bit number representing ori instruction.
+ */
+STATIC uint32_t getOriInstruction( const uint16_t i_Rs, const uint16_t i_Ra,
+ const uint16_t i_data )
+{
+ uint32_t oriInstOpcode = 0;
+ oriInstOpcode = 0;
+ oriInstOpcode = ORI_OPCODE << 26;
+ oriInstOpcode |= i_Rs << 21;
+ oriInstOpcode |= i_Ra << 16;
+ oriInstOpcode |= i_data;
+
+ return SWIZZLE_4_BYTE(oriInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates 32 bit key used for SPR lookup in core section.
+ */
+STATIC uint32_t genKeyForSprLookup( const CpuReg_t i_regId )
+{
+ return getOriInstruction( 0, 0, (uint16_t) i_regId );
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates xor instruction code.
+ * @param[in] i_Rs source register number for xor operation
+ * @param[in] i_Ra destination register number for xor operation result
+ * @param[in] i_Rb source register number for xor operation
+ * @return returns 32 bit number representing xor immediate instruction.
+ */
+STATIC uint32_t getXorInstruction( const uint16_t i_Ra, const uint16_t i_Rs,
+ const uint16_t i_Rb )
+{
+ uint32_t xorRegInstOpcode;
+ xorRegInstOpcode = XOR_CONST << 1;
+ xorRegInstOpcode |= OPCODE_31 << 26;
+ xorRegInstOpcode |= i_Rs << 21;
+ xorRegInstOpcode |= i_Ra << 16;
+ xorRegInstOpcode |= i_Rb << 11;
+
+ return SWIZZLE_4_BYTE(xorRegInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates oris instruction code.
+ * @param[in] i_Rs source register number
+ * @param[in] i_Ra destination register number
+ * @param[in] i_data 16 bit immediate data
+ * @return returns 32 bit number representing oris immediate instruction.
+ */
+STATIC uint32_t getOrisInstruction( const uint16_t i_Rs, const uint16_t i_Ra,
+ const uint16_t i_data )
+{
+ uint32_t orisInstOpcode;
+ orisInstOpcode = 0;
+ orisInstOpcode = ORIS_OPCODE << 26;
+ orisInstOpcode |= ( i_Rs & 0x001F ) << 21 | ( i_Ra & 0x001F ) << 16;
+ orisInstOpcode |= i_data;
+
+ return SWIZZLE_4_BYTE(orisInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates instruction for mtspr
+ * @param[in] i_Rs source register number
+ * @param[in] i_Spr represents spr where data is to be moved.
+ * @return returns 32 bit number representing mtspr instruction.
+ */
+STATIC uint32_t getMtsprInstruction( const uint16_t i_Rs, const uint16_t i_Spr )
+{
+ uint32_t mtsprInstOpcode = 0;
+ uint32_t temp = (( i_Spr & 0x03FF ) << 11);
+ mtsprInstOpcode = (uint8_t)i_Rs << 21;
+ mtsprInstOpcode |= ( temp & 0x0000F800 ) << 5;
+ mtsprInstOpcode |= ( temp & 0x001F0000 ) >> 5;
+ mtsprInstOpcode |= MTSPR_BASE_OPCODE;
+
+ return SWIZZLE_4_BYTE(mtsprInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates instruction for mfmsr
+ * @param[in] i_Rt target register for SPR content.
+ * @return returns 32 bit number representing mfmsr instruction.
+ */
+STATIC uint32_t getMfmsrInstruction( const uint16_t i_Rt )
+{
+ uint32_t mfmsrInstOpcode = ((OPCODE_31 << 26) | (i_Rt << 21) | (MFMSR_CONST));
+
+ return SWIZZLE_4_BYTE(mfmsrInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief generates rldicr instruction.
+ * @param[in] i_Rs source register number
+ * @param[in] i_Ra destination register number
+ * @param[in] i_sh bit position by which contents of i_Rs are to be shifted
+ * @param[in] i_me bit position up to which mask should be 1.
+ * @return returns 32 bit number representing rldicr instruction.
+ */
+STATIC uint32_t getRldicrInstruction( const uint16_t i_Ra, const uint16_t i_Rs,
+ const uint16_t i_sh, uint16_t i_me )
+{
+ uint32_t rldicrInstOpcode = 0;
+ rldicrInstOpcode = ((RLDICR_OPCODE << 26 ) | ( i_Rs << 21 ) | ( i_Ra << 16 ));
+ rldicrInstOpcode |= ( ( i_sh & 0x001F ) << 11 ) | (RLDICR_CONST << 2 );
+ rldicrInstOpcode |= (( i_sh & 0x0020 ) >> 4);
+ rldicrInstOpcode |= (i_me & 0x001F ) << 6;
+ rldicrInstOpcode |= (i_me & 0x0020 );
+ return SWIZZLE_4_BYTE(rldicrInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+STATIC uint32_t getMfsprInstruction( const uint16_t i_Rt, const uint16_t i_sprNum )
+{
+ uint32_t mfsprInstOpcode = 0;
+ mfsprInstOpcode = (( OPCODE_31 << 26 ) | ( i_Rt << 21 ) | ( i_sprNum << 11 ) | ( MFSPR_CONST << 1 ));
+ return SWIZZLE_4_BYTE(mfsprInstOpcode);
+}
+
+//-----------------------------------------------------------------------------
+
+STATIC uint32_t getBranchLinkRegInstruction(void)
+{
+ uint32_t branchConstInstOpcode = 0;
+ branchConstInstOpcode = (( OPCODE_18 << 26 ) | ( SELF_SAVE_FUNC_ADD ) | 0x03 );
+
+ return SWIZZLE_4_BYTE(branchConstInstOpcode);
+}
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief looks up entry for given SPR in given thread/core section.
+ * @param[in] i_pThreadSectLoc start of given thread section or core section.
+ * @param[in] i_lookUpKey search key for lookup of given SPR entry.
+ * @param[in] i_isThreadReg true if register is of scope thread, false
+ * otherwise.
+ * @param[in|out] io_pSprEntryLoc Input: NULL
+ * Output: location of given entry or end of table.
+ * @return STOP_SAVE_SUCCESS if entry is found, STOP_SAVE_FAIL in case of
+ * an error.
+ */
+STATIC StopReturnCode_t lookUpSprInImage( uint32_t* i_pThreadSectLoc, const uint32_t i_lookUpKey,
+ const bool i_isThreadReg, void** io_pSprEntryLoc,
+ uint8_t i_selfRestVer )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_FAIL;
+ uint32_t temp = 0;
+ uint32_t* i_threadSectEnd = NULL;
+ uint32_t bctr_inst = SWIZZLE_4_BYTE(BLR_INST);
+ *io_pSprEntryLoc = NULL;
+
+ do
+ {
+ if( !i_pThreadSectLoc )
+ {
+ MY_ERR( "Bad SPR Start Location" );
+ break;
+ }
+
+ if( i_selfRestVer )
+ {
+ temp = i_isThreadReg ? (uint32_t)(SMF_CORE_RESTORE_THREAD_AREA_SIZE) :
+ (uint32_t)(SMF_CORE_RESTORE_CORE_AREA_SIZE);
+
+ }
+ else
+ {
+ temp = i_isThreadReg ? (uint32_t)(CORE_RESTORE_THREAD_AREA_SIZE) :
+ (uint32_t)(CORE_RESTORE_CORE_AREA_SIZE);
+ }
+
+
+ i_threadSectEnd = i_pThreadSectLoc + ( temp >> 2 );
+
+ temp = 0;
+
+ while( ( i_pThreadSectLoc <= i_threadSectEnd ) &&
+ ( temp != bctr_inst ) )
+ {
+ temp = *i_pThreadSectLoc;
+
+ if( ( temp == i_lookUpKey ) || ( temp == bctr_inst ) )
+ {
+ *io_pSprEntryLoc = i_pThreadSectLoc;
+ l_rc = STOP_SAVE_SUCCESS;
+ break;
+ }
+
+ i_pThreadSectLoc = i_pThreadSectLoc + SIZE_PER_SPR_RESTORE_INST;
+ }
+ }
+ while(0);
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief updates an SPR STOP image entry.
+ * @param[in] i_pSprEntryLocation location of entry.
+ * @param[in] i_regId register Id associated with SPR.
+ * @param[in] i_regData data needs to be written to SPR entry.
+ * @return STOP_SAVE_SUCCESS if update works, STOP_SAVE_FAIL otherwise.
+ */
+STATIC StopReturnCode_t updateSprEntryInImage( uint32_t* i_pSprEntryLocation,
+ const CpuReg_t i_regId,
+ const uint64_t i_regData,
+ const enum SprEntryUpdateMode i_mode
+ )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ uint32_t tempInst = 0;
+ uint64_t tempRegData = 0;
+ bool newEntry = true;
+ uint16_t regRs = 0; //to use R0 for SPR restore insruction generation
+ uint16_t regRa = 0;
+
+ do
+ {
+ if( !i_pSprEntryLocation )
+ {
+ MY_ERR("invalid location of SPR image entry" );
+ l_rc = STOP_SAVE_FAIL;
+ break;
+ }
+
+ tempInst = genKeyForSprLookup( i_regId );
+
+ if( *i_pSprEntryLocation == tempInst )
+ {
+ newEntry = false;
+ }
+
+ //Add SPR search instruction i.e. "ori r0, r0, SPRID"
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ if( INIT_SPR_REGION == i_mode )
+ {
+ //adding inst 'b . + 0x1C'
+ *i_pSprEntryLocation = SWIZZLE_4_BYTE(SKIP_SPR_REST_INST);
+ }
+ else
+ {
+ //clear R0 i.e. "xor ra, rs, rb"
+ tempInst = getXorInstruction( regRs, regRs, regRs );
+ *i_pSprEntryLocation = tempInst;
+ }
+
+
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ tempRegData = i_regData >> 48;
+ //get lower order 16 bits of SPR restore value in R0
+ tempInst = getOrisInstruction( regRs, regRa, (uint16_t)tempRegData );
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ tempRegData = ((i_regData >> 32) & 0x0000FFFF );
+ //get bit b16-b31 of SPR restore value in R0
+ tempInst = getOriInstruction( regRs, regRa, (uint16_t)tempRegData );
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ //Rotate R0 to left by 32 bit position and zero lower order 32 bits.
+ //Place the result in R0
+ tempInst = getRldicrInstruction(regRa, regRs, 32, 31);
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ tempRegData = ((i_regData >> 16) & 0x000000FFFF );
+ //get bit b32-b47 of SPR restore value to R0
+ tempInst = getOrisInstruction( regRs, regRa, (uint16_t)tempRegData );
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ tempRegData = (uint16_t)i_regData;
+ //get bit b48-b63 of SPR restore value to R0
+ tempInst = getOriInstruction( regRs, regRa, (uint16_t)i_regData );
+ *i_pSprEntryLocation = tempInst;
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+
+ if( P9_STOP_SPR_MSR == i_regId )
+ {
+ //MSR cannot be restored completely with mtmsrd instruction.
+ //as it does not update ME, LE and HV bits. In self restore code
+ //inorder to restore MSR, contents of R21 is moved to SRR1. It also
+ //executes an RFID which causes contents of SRR1 to be copied to
+ //MSR. This allows copy of LE bit which are specifically interested
+ //in. Instruction below moves contents of MSR Value (in R0 ) to R21.
+ tempInst = SWIZZLE_4_BYTE( MR_R0_TO_R21 );
+ }
+ else if ( P9_STOP_SPR_HRMOR == i_regId )
+ {
+ //Case HRMOR, move contents of R0 to a placeholder GPR (R10)
+ //Thread Launcher expects HRMOR value in R10
+ tempInst = SWIZZLE_4_BYTE( MR_R0_TO_R10 );
+ }
+ else if( P9_STOP_SPR_URMOR == i_regId )
+ {
+ //Case URMOR, move contents of R0 to a placeholder GPR (R9)
+ //Thread Launcher expects URMOR value in R9
+ tempInst = SWIZZLE_4_BYTE( MR_R0_TO_R9 );
+ }
+ else
+ {
+ // Case other SPRs, move contents of R0 to SPR
+ // For a UV system, even HRMOR is treated like any other SPR.
+ tempInst =
+ getMtsprInstruction( 0, (uint16_t)i_regId );
+ }
+
+ *i_pSprEntryLocation = tempInst;
+
+ if( newEntry )
+ {
+ i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
+ //at the end of SPR restore, add instruction BLR to go back to thread
+ //launcher.
+ tempInst = SWIZZLE_4_BYTE(BLR_INST);
+ *i_pSprEntryLocation = tempInst;
+ }
+ }
+ while(0);
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+STATIC StopReturnCode_t initSelfSaveEntry( void* const i_pImage, uint16_t i_sprNum )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ uint32_t* i_pSprSave = (uint32_t*)i_pImage;
+
+ //ori r0, r0, 0x00nn
+ *i_pSprSave = getOriInstruction( 0, 0, i_sprNum );
+
+ i_pSprSave++;
+
+ //addi r31, r31, 0x20
+ *i_pSprSave = SWIZZLE_4_BYTE(SKIP_SPR_SELF_SAVE);
+ i_pSprSave++;
+
+ //nop
+ *i_pSprSave = getOriInstruction( 0, 0, 0 );;
+ i_pSprSave++;
+
+ //mtlr, r30
+ *i_pSprSave = SWIZZLE_4_BYTE( MTLR_INST );
+ i_pSprSave++;
+
+ //blr
+ *i_pSprSave = SWIZZLE_4_BYTE(BLR_INST);
+ i_pSprSave++;
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+STATIC StopReturnCode_t getSprRegIndexAdjustment( const uint32_t i_saveMaskPos, uint32_t* i_sprAdjIndex )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+
+ do
+ {
+ if( (( i_saveMaskPos >= SPR_BIT_POS_8 ) && ( i_saveMaskPos <= SPR_BIT_POS_19 )) ||
+ (( i_saveMaskPos >= SPR_BIT_POS_25 ) && ( i_saveMaskPos <= SPR_BIT_POS_27 )) )
+ {
+ l_rc = STOP_SAVE_SPR_BIT_POS_RESERVE;
+ break;
+ }
+
+ if( (i_saveMaskPos > SPR_BIT_POS_19) && (i_saveMaskPos < SPR_BIT_POS_25 ) )
+ {
+ *i_sprAdjIndex = 12;
+ }
+ else if( i_saveMaskPos > SPR_BIT_POS_27 )
+ {
+ *i_sprAdjIndex = 15;
+ }
+ else
+ {
+ *i_sprAdjIndex = 0;
+ }
+
+ }
+ while(0);
+
+ return l_rc;
+}
+//-----------------------------------------------------------------------------
+StopReturnCode_t p9_stop_save_cpureg( void* const i_pImage,
+ const CpuReg_t i_regId,
+ const uint64_t i_regData,
+ const uint64_t i_pir )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS; // procedure return code
+ HomerSection_t* chipHomer = NULL;
+ SmfHomerSection_t* smfChipHomer = NULL;
+
+ do
+ {
+ uint32_t threadId = 0;
+ uint32_t coreId = 0;
+ uint32_t lookUpKey = 0;
+ void* pSprEntryLocation = NULL; // an offset w.r.t. to start of image
+ void* pThreadLocation = NULL;
+ bool threadScopeReg = false;
+ uint8_t l_urmorFix = false;
+ uint64_t l_sprValue = 0;
+ uint8_t l_selfRestVer = 0;
+
+ MY_INF(">> p9_stop_save_cpureg" );
+
+ l_rc = getCoreAndThread( i_pImage, i_pir, &coreId, &threadId );
+
+ if( l_rc )
+ {
+ MY_ERR("Failed to determine Core Id and Thread Id from PIR 0x%016llx",
+ i_pir);
+ break;
+ }
+
+ MY_INF( " PIR 0x%016llx coreId %d threadid %d "
+ " registerId %d", i_pir, coreId,
+ threadId, i_regId );
+
+ // First of all let us validate all input arguments.
+ l_rc = validateSprImageInputs( i_pImage,
+ i_regId,
+ coreId,
+ &threadId,
+ &threadScopeReg );
+
+ if( l_rc )
+ {
+ // Error: bad argument traces out error code
+ MY_ERR("Bad input argument rc %d", l_rc );
+
+ break;
+ }
+
+ l_urmorFix = *(uint8_t*)((uint8_t*)i_pImage + CPMR_HOMER_OFFSET + CPMR_URMOR_FIX_BYTE);
+ l_selfRestVer = *(uint8_t *)((uint8_t *)i_pImage + CPMR_HOMER_OFFSET + CPMR_SELF_RESTORE_VER_BYTE );
+
+ if( l_selfRestVer )
+ {
+ smfChipHomer = ( SmfHomerSection_t*)i_pImage;
+
+ if( threadScopeReg )
+ {
+ pThreadLocation =
+ &(smfChipHomer->iv_coreThreadRestore[coreId].iv_threadRestoreArea[threadId][0]);
+ }
+ else
+ {
+ pThreadLocation =
+ &(smfChipHomer->iv_coreThreadRestore[coreId].iv_coreRestoreArea[0]);
+ }
+ }
+ else //Old fips or OPAL release that doesn't support SMF
+ {
+ chipHomer = (HomerSection_t*)i_pImage;
+
+ if( threadScopeReg )
+ {
+ pThreadLocation =
+ &(chipHomer->iv_coreThreadRestore[coreId][threadId].iv_threadArea[0]);
+ }
+ else
+ {
+ pThreadLocation =
+ &(chipHomer->iv_coreThreadRestore[coreId][threadId].iv_coreArea[0]);
+ }
+ }
+
+ if( ( SWIZZLE_4_BYTE(BLR_INST) == *(uint32_t*)pThreadLocation ) ||
+ ( SWIZZLE_4_BYTE(ATTN_OPCODE) == *(uint32_t*) pThreadLocation ) )
+ {
+ // table for given core id doesn't exit. It needs to be
+ // defined.
+ pSprEntryLocation = pThreadLocation;
+ }
+ else
+ {
+ // an SPR restore section for given core already exists
+ lookUpKey = genKeyForSprLookup( i_regId );
+ l_rc = lookUpSprInImage( (uint32_t*)pThreadLocation,
+ lookUpKey,
+ threadScopeReg,
+ &pSprEntryLocation,
+ l_selfRestVer );
+ }
+
+ if( l_rc )
+ {
+ MY_ERR("Invalid or corrupt SPR entry. CoreId 0x%08x threadId ",
+ "0x%08x regId 0x%08x lookUpKey 0x%08x pThreadLocation 0x%08x"
+ , coreId, threadId, i_regId, lookUpKey, pThreadLocation );
+ break;
+ }
+
+ if( ( P9_STOP_SPR_URMOR == i_regId ) && ( l_urmorFix ) )
+ {
+ l_sprValue = i_regData - URMOR_CORRECTION;
+ }
+ else
+ {
+ l_sprValue = i_regData;
+ }
+
+ l_rc = updateSprEntryInImage( (uint32_t*) pSprEntryLocation,
+ i_regId,
+ l_sprValue,
+ UPDATE_SPR_ENTRY );
+
+ if( l_rc )
+ {
+ MY_ERR( " Failed to update the SPR entry of PIR 0x%08x reg"
+ "0x%08x", i_pir, i_regId );
+ break;
+ }
+
+ }
+ while(0);
+
+ MY_INF("<< p9_stop_save_cpureg" );
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief validates all the input arguments.
+ * @param[in] i_pImage pointer to start of HOMER of image for proc chip.
+ * @param[in] i_scomAddress SCOM address of register.
+ * @param[in] i_chipletId core or cache chiplet id
+ * @param[in] i_operation operation requested for SCOM entry.
+ * @param[in] i_section image section on which operation is to be performed
+ * @return STOP_SAVE_SUCCESS if arguments found valid, error code otherwise.
+ * @note Function does not validate that the given SCOM address really
+ * belongs to the given section.
+ */
+STATIC StopReturnCode_t validateScomImageInputs( void* const i_pImage,
+ const uint32_t i_scomAddress,
+ const uint8_t i_chipletId,
+ const ScomOperation_t i_operation,
+ const ScomSection_t i_section )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+
+ do
+ {
+ if( !i_pImage )
+ {
+ //Error Invalid image pointer
+ l_rc = STOP_SAVE_ARG_INVALID_IMG;
+ MY_ERR("invalid image location ");
+ break;
+ }
+
+ if( 0 == i_scomAddress )
+ {
+ l_rc = STOP_SAVE_SCOM_INVALID_ADDRESS;
+ MY_ERR("invalid SCOM address");
+ break;
+ }
+
+ if(( CACHE_CHIPLET_ID_MIN > i_chipletId ) ||
+ ( CORE_CHIPLET_ID_MAX < i_chipletId ))
+ {
+ l_rc = STOP_SAVE_SCOM_INVALID_CHIPLET;
+ MY_ERR("chiplet id not in range");
+ break;
+ }
+
+ if(( CORE_CHIPLET_ID_MIN > i_chipletId ) &&
+ ( CACHE_CHIPLET_ID_MAX < i_chipletId ))
+ {
+ l_rc = STOP_SAVE_SCOM_INVALID_CHIPLET;
+ MY_ERR("chiplet id not valid");
+ break;
+ }
+
+ if(( P9_STOP_SCOM_OP_MIN >= i_operation ) ||
+ ( P9_STOP_SCOM_OP_MAX <= i_operation ))
+ {
+ //invalid SCOM image operation requested
+ l_rc = STOP_SAVE_SCOM_INVALID_OPERATION;
+ MY_ERR("invalid SCOM image operation");
+ break;
+ }
+
+ if(( P9_STOP_SECTION_MIN >= i_section ) ||
+ ( P9_STOP_SECTION_MAX <= i_section ))
+ {
+ // invalid cache sub section specified
+ l_rc = STOP_SAVE_SCOM_INVALID_SECTION;
+ MY_ERR("invalid section");
+ break;
+ }
+
+ if(( i_operation == P9_STOP_SCOM_RESET ) &&
+ ( i_chipletId < CORE_CHIPLET_ID_MIN ))
+ {
+ // replace requested with a cache chiplet Id
+ l_rc = STOP_SAVE_SCOM_INVALID_OPERATION;
+ MY_ERR( "reset not supported for cache. chiplet Id 0x%08x",
+ i_chipletId );
+ break;
+ }
+
+ }
+ while(0);
+
+ if( l_rc )
+ {
+ MY_ERR("image 0x%08x SCOMAddress 0x%08x chipletId 0x%08x operation"
+ "0x%08x section 0x%08x", i_pImage, i_scomAddress, i_chipletId,
+ i_operation, i_section );
+ }
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief edit SCOM entry associated with the given core.
+ * @param[in] i_scomAddr SCOM address of register.
+ * @param[in] i_scomData data associated with SCOM register.
+ * @param[in] i_pEntryLocation points to a SCOM entry in HOMER image.
+ * @param[in] i_operation operation to be performed on SCOM entry.
+ * @return STOP_SAVE_SUCCESS if existing entry is updated, STOP_SAVE_FAIL
+ * otherwise.
+ */
+STATIC StopReturnCode_t editScomEntry( uint32_t i_scomAddr, uint64_t i_scomData,
+ ScomEntry_t* i_pEntryLocation,
+ uint32_t i_operation )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+
+ do
+ {
+ if( !i_pEntryLocation )
+ {
+ //Error: location of SCOM entry is not known
+ //therefore no point moving forward
+ MY_ERR("SCOM entry location not valid");
+ l_rc = STOP_SAVE_FAIL;
+ break;
+ }
+
+ switch( i_operation )
+ {
+ case P9_STOP_SCOM_OR:
+ i_pEntryLocation->scomEntryData |= i_scomData;
+ break;
+
+ case P9_STOP_SCOM_AND:
+ i_pEntryLocation->scomEntryData &= i_scomData;
+ break;
+
+ case P9_STOP_SCOM_NOOP:
+ {
+ uint32_t nopInst = getOriInstruction( 0, 0, 0 );
+ i_pEntryLocation->scomEntryHeader = SWIZZLE_4_BYTE(SCOM_ENTRY_START);
+ i_pEntryLocation->scomEntryData = nopInst;
+ i_pEntryLocation->scomEntryAddress = nopInst;
+ }
+ break;
+
+ case P9_STOP_SCOM_APPEND:
+ i_pEntryLocation->scomEntryHeader = SWIZZLE_4_BYTE(SCOM_ENTRY_START);
+ i_pEntryLocation->scomEntryData = i_scomData;
+ i_pEntryLocation->scomEntryAddress = i_scomAddr;
+ break;
+ }
+
+ }
+ while(0);
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief update SCOM entry associated with the given core.
+ * @param[in] i_scomAddr SCOM address of register.
+ * @param[in] i_scomData data associated with SCOM register.
+ * @param[in] i_scomEntry points to a SCOM entry in cache section of HOMER image.
+ * @return STOP_SAVE_SUCCESS if new entry is added, STOP_SAVE_FAIL otherwise.
+ * @note adds an entry at a given location. It can be used to add entry in
+ * place of NOP, at the end of table or as first entry of the cache
+ * sub-section(L2, L3 or EQ ).
+ */
+STATIC StopReturnCode_t updateScomEntry( uint32_t i_scomAddr, uint64_t i_scomData,
+ ScomEntry_t* i_scomEntry )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+
+ do
+ {
+ if( !i_scomEntry )
+ {
+ MY_ERR( "cache entry cannot be located");
+ l_rc = STOP_SAVE_SCOM_ENTRY_UPDATE_FAILED;
+ break;
+ }
+
+ i_scomEntry->scomEntryHeader = SWIZZLE_4_BYTE(SCOM_ENTRY_START); // done for now
+ i_scomEntry->scomEntryAddress = i_scomAddr;
+ i_scomEntry->scomEntryData = i_scomData;
+
+ }
+ while(0);
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+/**
+ * @brief populates SCOM restore entry header with version and layout info.
+ * @param[in] i_scomEntry points to SCOM restore entry
+ * @param[in] i_imageVer SGPE image version
+ * @param[in] i_maxScomEntry max SCOM entries supported
+ */
+
+STATIC void updateEntryHeader( ScomEntry_t* i_scomEntry ,
+ uint32_t i_imageVer,
+ uint32_t i_maxScomEntry )
+{
+ uint32_t l_temp = 0;
+
+ if( i_imageVer >= STOP_API_VER_CONTROL )
+ {
+ l_temp = ( 0x000000ff & i_maxScomEntry );
+ l_temp |= ( STOP_API_VER & 0x7 ) << 28;
+ i_scomEntry->scomEntryHeader = SWIZZLE_4_BYTE(l_temp);
+
+ MY_INF("SCOM Restore Header 0x%08x", l_temp );
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+StopReturnCode_t p9_stop_save_scom( void* const i_pImage,
+ const uint32_t i_scomAddress,
+ const uint64_t i_scomData,
+ const ScomOperation_t i_operation,
+ const ScomSection_t i_section )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ uint32_t entryLimit = 0;
+ uint8_t chipletId = 0;
+ uint32_t nopInst = 0;
+ uint32_t index = 0;
+ uint32_t imageVer = 0;
+ uint32_t entrySwzHeader = 0;
+ uint32_t l_maxScomRestoreEntry = 0;
+ ScomEntry_t* pScomEntry = NULL;
+ ScomEntry_t* pEntryLocation = NULL;
+ ScomEntry_t* pNopLocation = NULL;
+ ScomEntry_t* pEditScomHeader = NULL;
+ StopCacheSection_t* pStopCacheScomStart = NULL;
+ ScomEntry_t* pTableEndLocationtable = NULL;
+ uint32_t swizzleAddr;
+ uint64_t swizzleData;
+ uint32_t swizzleAttn;
+ uint32_t swizzleBlr = SWIZZLE_4_BYTE(BLR_INST);
+ bool cacheEntry = true;
+
+ MY_INF(">> p9_stop_save_scom");
+
+ //Reads SGPE image version info from QPMR Header in HOMER
+ //For backward compatibility, for base version of SGPE Hcode,
+ //STOP API retains default behavior but adds version specific
+ //details in each entry in later versions.
+ imageVer = *(uint32_t*)((uint8_t*)i_pImage + QPMR_HOMER_OFFSET + QPMR_BUILD_VER_BYTE);
+ imageVer = SWIZZLE_4_BYTE(imageVer);
+
+
+ do
+ {
+ chipletId = i_scomAddress >> 24;
+ chipletId = chipletId & 0x3F;
+
+ l_rc = validateScomImageInputs( i_pImage, i_scomAddress, chipletId, i_operation, i_section );
+
+ if( l_rc )
+ {
+ MY_ERR( "invalid argument: aborting");
+ break;
+ }
+
+ if( chipletId >= CORE_CHIPLET_ID_MIN )
+ {
+ // chiplet is core. So, let us find the start address of SCOM area
+ // pertaining to a core in STOP image.
+ l_maxScomRestoreEntry =
+ *(uint32_t*)((uint8_t*)i_pImage + CPMR_HOMER_OFFSET + CPMR_MAX_SCOM_REST_PER_CORE_BYTE);
+ pScomEntry = CORE_ID_SCOM_START(i_pImage, chipletId )
+ cacheEntry = false;
+
+ if( !l_maxScomRestoreEntry )
+ {
+ //Old HB and new STOP API case. Retain legacy Number
+ l_maxScomRestoreEntry = SWIZZLE_4_BYTE(LEGACY_CORE_SCOM_SUPPORTED);
+ }
+ }
+ else
+ {
+ l_maxScomRestoreEntry =
+ *(uint32_t*)((uint8_t*)i_pImage + QPMR_HOMER_OFFSET + QPMR_QUAD_MAX_SCOM_ENTRY_BYTE);
+
+ if( !l_maxScomRestoreEntry )
+ {
+ // Incase of a bad HOMER header initialization, fall back on legacy number.
+ l_maxScomRestoreEntry = SWIZZLE_4_BYTE(LEGACY_QUAD_SCOM_SUPPORTED);
+ }
+ // chiplet is a cache. let us find start address of cache section
+ // associated with given chiplet. A cache section associated with
+ // given chiplet is split in to L2, L3 and EQ area.
+ pStopCacheScomStart = CACHE_SECTN_START(i_pImage,
+ chipletId);
+ }
+
+ l_maxScomRestoreEntry = SWIZZLE_4_BYTE(l_maxScomRestoreEntry);
+
+ if(( !pStopCacheScomStart ) && ( !pScomEntry) )
+ {
+ //Error invalid pointer to SCOM entry in cache or core section
+ //of STOP image.
+ MY_ERR("invalid start location for chiplet %d",
+ chipletId );
+ break;
+ }
+
+ switch( i_section )
+ {
+ case P9_STOP_SECTION_EQ_SCOM:
+ pScomEntry = pStopCacheScomStart->nonCacheArea;
+ entryLimit = MAX_EQ_SCOM_ENTRIES;
+ break;
+
+ case P9_STOP_SECTION_L2:
+ pScomEntry = pStopCacheScomStart->l2CacheArea;
+ entryLimit = MAX_L2_SCOM_ENTRIES;
+ break;
+
+ case P9_STOP_SECTION_L3:
+ pScomEntry = pStopCacheScomStart->l3CacheArea;
+ entryLimit = MAX_L3_SCOM_ENTRIES;
+ break;
+
+ case P9_STOP_SECTION_CORE_SCOM:
+ //macro CORE_ID_SCOM_START already gives start of scom
+ //entry for given core. entry limit too is assigned thereafter.
+ //Handling for core and cache segment is different for scom
+ //entries. It is because scom entries are organized differently
+ //in core and cache segment.
+
+ entryLimit = l_maxScomRestoreEntry;
+ break;
+
+ default:
+ l_rc = STOP_SAVE_SCOM_INVALID_SECTION;
+ break;
+ }
+
+
+ if(( imageVer > LEGACY_SCOM_RESTORE_VER ) && ( cacheEntry ) )
+ {
+ //STOP API migrated to newer algorithm for creation of entries
+
+ pScomEntry = CACHE_SCOM_ADDR(i_pImage,
+ chipletId,
+ l_maxScomRestoreEntry )
+
+ entryLimit = l_maxScomRestoreEntry;
+ }
+
+ if(( !pScomEntry ) || ( l_rc ) )
+ {
+ // Error Invalid pointer to cache entry
+ MY_ERR("invalid subsection %d or internal firmware failure",
+ i_section );
+ l_rc = STOP_SAVE_FAIL;
+ break;
+ }
+
+ nopInst = getOriInstruction( 0, 0, 0 );
+ pEntryLocation = NULL;
+ pNopLocation = NULL;
+ pTableEndLocationtable = NULL;
+ swizzleAddr = SWIZZLE_4_BYTE(i_scomAddress);
+ swizzleData = SWIZZLE_8_BYTE(i_scomData);
+ swizzleAttn = SWIZZLE_4_BYTE(ATTN_OPCODE);
+
+ for( index = 0; index < entryLimit; ++index )
+ {
+ uint32_t entrySwzAddress = pScomEntry[index].scomEntryAddress;
+ entrySwzHeader = SWIZZLE_4_BYTE(pScomEntry[index].scomEntryHeader);
+
+ if( ( swizzleAddr == entrySwzAddress ) && ( !pEntryLocation ) )
+
+ {
+ pEntryLocation = &pScomEntry[index];
+ }
+
+ if( (( nopInst == entrySwzAddress ) ||
+ ( swizzleAttn == entrySwzAddress ) ||
+ ( swizzleBlr == entrySwzAddress )) && ( !pNopLocation ) )
+ {
+ pNopLocation = &pScomEntry[index];
+ }
+
+ // if entry is either 0xDEADDEAD or has SCOM entry limit in LSB of header
+ // place is already occupied
+ if( ( SCOM_ENTRY_START == entrySwzHeader ) ||
+ ( entrySwzHeader & 0x000000FF ) )
+ {
+ continue;
+ }
+
+ pTableEndLocationtable = &pScomEntry[index];
+ break;
+ }
+
+ if( ( !pEntryLocation ) && ( !pTableEndLocationtable ) )
+ {
+ MY_ERR(" exhausted all location available for section"
+ "0x%08x scom address 0x%08x",
+ i_section, i_scomAddress );
+ l_rc = STOP_SAVE_SCOM_ENTRY_UPDATE_FAILED;
+ break;
+ }
+
+ switch( i_operation )
+ {
+ case P9_STOP_SCOM_APPEND:
+ {
+ ScomEntry_t* pScomAppend = NULL;
+
+ if( pNopLocation )
+ {
+ pScomAppend = pNopLocation;
+ }
+ else
+ {
+ pScomAppend = pTableEndLocationtable;
+ }
+
+ l_rc = updateScomEntry ( swizzleAddr,
+ swizzleData, pScomAppend );
+
+ pEditScomHeader = pScomAppend;
+ }
+ break;
+
+ case P9_STOP_SCOM_REPLACE:
+ {
+ ScomEntry_t* scomReplace = NULL;
+
+ if( pEntryLocation )
+ {
+ scomReplace = pEntryLocation;
+ }
+ else
+ {
+ scomReplace = pTableEndLocationtable;
+ }
+
+ l_rc = updateScomEntry( swizzleAddr,
+ swizzleData, scomReplace );
+
+ pEditScomHeader = scomReplace;
+ }
+ break;
+
+ case P9_STOP_SCOM_OR:
+ case P9_STOP_SCOM_AND:
+ case P9_STOP_SCOM_NOOP:
+
+ if( pEntryLocation )
+ {
+ l_rc = editScomEntry( swizzleAddr,
+ swizzleData,
+ pEntryLocation,
+ i_operation );
+
+ pEditScomHeader = pEntryLocation;
+ }
+ else
+ {
+ //Invalid operation requested.
+ MY_ERR( "entry not found edit chiplet Id 0x%08x "
+ "swizzle addr 0x%08x ",
+ chipletId, swizzleAddr );
+
+ l_rc = STOP_SAVE_SCOM_INVALID_OPERATION;
+ }
+
+ break;
+
+ case P9_STOP_SCOM_RESET:
+
+ if( P9_STOP_SECTION_CORE_SCOM == i_section )
+ {
+ memset( pScomEntry, 0x00, CORE_SCOM_RESTORE_SIZE_PER_CORE );
+ }
+
+ break;
+
+ case P9_STOP_SCOM_OR_APPEND:
+ case P9_STOP_SCOM_AND_APPEND:
+ {
+ uint32_t tempOperation = P9_STOP_SCOM_APPEND;
+ ScomEntry_t* editAppend = NULL;
+
+ if( NULL == pEntryLocation )
+ {
+ editAppend = pTableEndLocationtable;
+ }
+ else
+ {
+ editAppend = pEntryLocation;
+
+ if( P9_STOP_SCOM_OR_APPEND == i_operation )
+ {
+ tempOperation = P9_STOP_SCOM_OR;
+ }
+ else
+ {
+ tempOperation = P9_STOP_SCOM_AND;
+ }
+ }
+
+ l_rc = editScomEntry( swizzleAddr,
+ swizzleData,
+ editAppend,
+ tempOperation );
+
+ pEditScomHeader = editAppend;
+ }
+ break;
+
+ default:
+ l_rc = STOP_SAVE_SCOM_INVALID_OPERATION;
+ break;
+ }
+ }
+ while(0);
+
+ if( l_rc )
+ {
+ MY_ERR("SCOM image operation 0x%08x failed for chiplet 0x%08x addr"
+ "0x%08x", i_operation, chipletId ,
+ i_scomAddress );
+ }
+ else
+ {
+ //Update SCOM Restore entry with version and memory layout
+ //info
+ updateEntryHeader( pEditScomHeader, imageVer, l_maxScomRestoreEntry );
+ }
+
+ MY_INF("<< p9_stop_save_scom");
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief searches a self save entry of an SPR in self-save segment.
+ * @param[in] i_sprBitPos bit position associated with SPR in save mask vector.
+ * @param[in] l_pSprSaveStart start location of SPR save segment
+ * @param[in] i_searchLength length of SPR save segment
+ * @param[in] i_pSaveSprLoc start location of save entry for a given SPR.
+ * @return STOP_SAVE_SUCCESS if look up succeeds, error code otherwise.
+ */
+STATIC StopReturnCode_t lookUpSelfSaveSpr( uint32_t i_sprBitPos, uint32_t* l_pSprSaveStart,
+ uint32_t i_searchLength, uint32_t** i_pSaveSprLoc )
+{
+ int32_t l_saveWordLength = (int32_t)(i_searchLength >> 2);
+ uint32_t l_oriInst = getOriInstruction( 0, 0, i_sprBitPos );
+ StopReturnCode_t l_rc = STOP_SAVE_FAIL;
+
+ while( l_saveWordLength > 0 )
+ {
+ if( l_oriInst == *l_pSprSaveStart )
+ {
+ *i_pSaveSprLoc = l_pSprSaveStart;
+ l_rc = STOP_SAVE_SUCCESS;
+ break;
+ }
+
+ l_pSprSaveStart++;
+ l_saveWordLength--;
+ }
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief searches a self save entry of an SPR in self-save segment.
+ * @param[in] i_pSaveReg start of editable location of a SPR save entry.
+ * @param[in] i_sprNum Id of the SPR for which entry needs to be edited.
+ * @return STOP_SAVE_SUCCESS if look up succeeds, error code otherwise.
+ */
+STATIC StopReturnCode_t updateSelfSaveEntry( uint32_t* i_pSaveReg, uint16_t i_sprNum )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+
+ do
+ {
+ if( !i_pSaveReg )
+ {
+ l_rc = STOP_SAVE_FAIL;
+ MY_ERR( "Failed to update self save area for SPR 0x%04x", i_sprNum );
+ break;
+ }
+
+ if( P9_STOP_SPR_MSR == i_sprNum )
+ {
+ *i_pSaveReg = getMfmsrInstruction( 1 );
+ }
+ else
+ {
+ *i_pSaveReg = getMfsprInstruction( 1, i_sprNum );
+ }
+
+ i_pSaveReg++;
+
+ *i_pSaveReg = getBranchLinkRegInstruction( );
+ }
+ while(0);
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------
+
+StopReturnCode_t p9_stop_save_cpureg_control( void* i_pImage,
+ const uint64_t i_pir,
+ const uint32_t i_saveRegVector )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ uint32_t l_coreId = 0;
+ uint32_t l_threadId = 0;
+ uint32_t l_sprPos = 0;
+ uint32_t l_sprIndex = 0;
+ uint32_t l_lookupLength = 0;
+ uint32_t l_lookUpKey = 0;
+ uint32_t* l_pSaveStart = NULL;
+ uint32_t* l_pRestoreStart = NULL;
+ uint32_t* l_pSprSave = NULL;
+ void* l_pTempLoc = NULL;
+ SmfHomerSection_t* l_pHomer = NULL;
+ uint8_t l_selfRestVer = 0;
+
+ do
+ {
+ l_rc = getCoreAndThread( i_pImage, i_pir, &l_coreId, &l_threadId );
+
+ if( l_rc )
+ {
+ MY_ERR( "Error in getting core no 0x%08x and thread no 0x%08x from PIR 0x%016lx",
+ l_coreId, l_threadId, i_pir );
+ break;
+ }
+
+ l_rc = validateArgumentSaveRegMask( i_pImage, l_coreId, l_threadId, i_saveRegVector );
+
+ if( l_rc )
+ {
+ MY_ERR( "Invalid argument rc 0x%08x", (uint32_t) l_rc );
+ break;
+ }
+
+ l_pHomer = ( SmfHomerSection_t * )i_pImage;
+ l_selfRestVer = *(uint8_t *)((uint8_t *)i_pImage + CPMR_HOMER_OFFSET + CPMR_SELF_RESTORE_VER_BYTE );
+
+ for( l_sprIndex = 0; l_sprIndex < MAX_SPR_SUPPORTED; l_sprIndex++ )
+ {
+ l_sprPos = g_sprRegister[l_sprIndex].iv_saveMaskPos;
+
+ //Check if a given SPR needs to be self-saved each time on STOP entry
+
+ if( i_saveRegVector & ( TEST_BIT_PATTERN >> l_sprPos ) )
+ {
+
+ if( g_sprRegister[l_sprIndex].iv_isThreadScope )
+ {
+ l_lookupLength = SMF_SELF_SAVE_THREAD_AREA_SIZE;
+ l_pSaveStart =
+ (uint32_t*)&l_pHomer->iv_coreThreadRestore[l_coreId].iv_threadSaveArea[l_threadId][0];
+ l_pRestoreStart =
+ (uint32_t*)&l_pHomer->iv_coreThreadRestore[l_coreId].iv_threadRestoreArea[l_threadId][0];
+ }
+ else
+ {
+ l_lookupLength = SMF_CORE_SAVE_CORE_AREA_SIZE;
+ l_pSaveStart = (uint32_t*)&l_pHomer->iv_coreThreadRestore[l_coreId].iv_coreSaveArea[0];
+ l_pRestoreStart = (uint32_t*)&l_pHomer->iv_coreThreadRestore[l_coreId].iv_coreRestoreArea[0];
+ }
+
+ // an SPR restore section for given core already exists
+ l_lookUpKey = genKeyForSprLookup( ( CpuReg_t )g_sprRegister[l_sprIndex].iv_sprId );
+
+ l_rc = lookUpSprInImage( (uint32_t*)l_pRestoreStart, l_lookUpKey,
+ g_sprRegister[l_sprIndex].iv_isThreadScope, &l_pTempLoc,
+ l_selfRestVer );
+
+ if( l_rc )
+ {
+ //SPR specified in the save mask but there is no restore entry present in the memory
+ //Self-Save instruction will edit it during STOP entry to make it a valid entry
+
+ l_rc = p9_stop_save_cpureg( i_pImage,
+ (CpuReg_t)g_sprRegister[l_sprIndex].iv_sprId,
+ 0x00, //creates a dummy entry
+ i_pir );
+ }
+
+ //Find if SPR-Save eye catcher exist in self-save segment of SPR restore region.
+ l_rc = lookUpSelfSaveSpr( l_sprPos, l_pSaveStart, l_lookupLength, &l_pSprSave );
+
+ if( l_rc )
+ {
+ MY_INF( "Failed to find SPR No %02d save entry", l_sprPos );
+ l_rc = STOP_SAVE_SPR_ENTRY_MISSING;
+ break;
+ }
+
+ l_pSprSave++; //point to next instruction location
+
+ //update specific instructions of self save region to enable saving for SPR
+ l_rc = updateSelfSaveEntry( l_pSprSave, g_sprRegister[l_sprIndex].iv_sprId );
+
+ }// end if( i_saveRegVector..)
+ }// end for
+ }
+ while(0);
+
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------------------------------
+
+StopReturnCode_t p9_stop_init_cpureg( void* const i_pImage, const uint32_t i_corePos )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ uint32_t* l_pRestoreStart = NULL;
+ void* l_pTempLoc = NULL;
+ SmfHomerSection_t* l_pHomer = NULL;
+ uint32_t l_threadPos = 0;
+ uint32_t l_lookUpKey = 0;
+ uint32_t l_sprIndex = 0;
+ uint8_t l_selfRestVer = 0;
+
+ MY_INF( ">> p9_stop_init_cpureg" );
+
+ do
+ {
+ if( !i_pImage )
+ {
+ l_rc = STOP_SAVE_ARG_INVALID_IMG;
+ break;
+ }
+
+ if( i_corePos > MAX_CORE_ID_SUPPORTED )
+ {
+ l_rc = STOP_SAVE_ARG_INVALID_CORE;
+ break;
+ }
+
+ l_pHomer = ( SmfHomerSection_t * ) i_pImage;
+ l_selfRestVer = *(uint8_t *)((uint8_t *)i_pImage + CPMR_HOMER_OFFSET + CPMR_SELF_RESTORE_VER_BYTE );
+
+ for( l_sprIndex = 0; l_sprIndex < MAX_SPR_SUPPORTED; l_sprIndex++ )
+ {
+ //Check if a given SPR needs to be self-saved each time on STOP entry
+
+ l_lookUpKey = genKeyForSprLookup( ( CpuReg_t )g_sprRegister[l_sprIndex].iv_sprId );
+
+ if( g_sprRegister[l_sprIndex].iv_isThreadScope )
+ {
+ for( l_threadPos = 0; l_threadPos < MAX_THREADS_PER_CORE; l_threadPos++ )
+ {
+ l_pRestoreStart =
+ (uint32_t*)&l_pHomer->iv_coreThreadRestore[i_corePos].iv_threadRestoreArea[l_threadPos][0];
+
+ l_rc = lookUpSprInImage( (uint32_t*)l_pRestoreStart, l_lookUpKey,
+ g_sprRegister[l_sprIndex].iv_isThreadScope,
+ &l_pTempLoc,
+ l_selfRestVer );
+
+ if( l_rc )
+ {
+ MY_ERR( "Thread SPR lookup failed in p9_stop_init_cpureg SPR %d Core %d Thread %d Index %d",
+ g_sprRegister[l_sprIndex].iv_sprId, i_corePos, l_threadPos, l_sprIndex );
+ break;
+ }
+
+ l_rc = updateSprEntryInImage( (uint32_t*) l_pTempLoc,
+ ( CpuReg_t )g_sprRegister[l_sprIndex].iv_sprId,
+ 0x00,
+ INIT_SPR_REGION );
+
+ if( l_rc )
+ {
+ MY_ERR( "Thread SPR region init failed. Core %d SPR Id %d",
+ i_corePos, g_sprRegister[l_sprIndex].iv_sprId );
+ break;
+ }
+
+ }//end for thread
+
+ if( l_rc )
+ {
+ break;
+ }
+
+ }//end if SPR threadscope
+ else
+ {
+ l_pRestoreStart = (uint32_t*)&l_pHomer->iv_coreThreadRestore[i_corePos].iv_coreRestoreArea[0];
+
+ l_rc = lookUpSprInImage( (uint32_t*)l_pRestoreStart, l_lookUpKey,
+ g_sprRegister[l_sprIndex].iv_isThreadScope,
+ &l_pTempLoc, l_selfRestVer );
+
+ if( l_rc )
+ {
+ MY_ERR( "Core SPR lookup failed in p9_stop_init_cpureg" );
+ break;
+ }
+
+ l_rc = updateSprEntryInImage( (uint32_t*) l_pTempLoc,
+ ( CpuReg_t )g_sprRegister[l_sprIndex].iv_sprId,
+ 0x00,
+ INIT_SPR_REGION );
+
+ if( l_rc )
+ {
+ MY_ERR( "Core SPR region init failed. Core %d SPR Id %d SPR Index %d",
+ i_corePos, g_sprRegister[l_sprIndex].iv_sprId, l_sprIndex );
+ break;
+ }
+
+ }// end else
+
+ }// end for l_sprIndex
+
+ }
+ while(0);
+
+ MY_INF( "<< p9_stop_init_cpureg" );
+ return l_rc;
+}
+
+//-----------------------------------------------------------------------------------------------------
+
+StopReturnCode_t p9_stop_init_self_save( void* const i_pImage, const uint32_t i_corePos )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ uint32_t* l_pSaveStart = NULL;
+ SmfHomerSection_t * l_pHomer = NULL;
+ uint32_t l_threadPos = 0;
+ uint32_t l_sprBitPos = 0;
+ uint32_t l_sprIndexAdj = 0;
+ MY_INF( ">> p9_stop_init_self_save" );
+
+ do
+ {
+ if( !i_pImage )
+ {
+ l_rc = STOP_SAVE_ARG_INVALID_IMG;
+ break;
+ }
+
+ if( i_corePos > MAX_CORE_ID_SUPPORTED )
+ {
+ l_rc = STOP_SAVE_ARG_INVALID_CORE;
+ break;
+ }
+
+ l_pHomer = ( SmfHomerSection_t*) i_pImage;
+
+ for( l_threadPos = 0; l_threadPos < MAX_THREADS_PER_CORE; l_threadPos++ )
+ {
+ l_pSaveStart =
+ (uint32_t*)&l_pHomer->iv_coreThreadRestore[i_corePos].iv_threadSaveArea[l_threadPos][0];
+
+ //Adding instruction 'mflr r30'
+ *l_pSaveStart = SWIZZLE_4_BYTE(MFLR_R30);
+ l_pSaveStart++;
+
+ for( l_sprBitPos = 0; l_sprBitPos <= MAX_SPR_BIT_POS; l_sprBitPos++ )
+ {
+ l_rc = getSprRegIndexAdjustment( l_sprBitPos, &l_sprIndexAdj );
+
+ if( STOP_SAVE_SPR_BIT_POS_RESERVE == l_rc )
+ {
+ //Failed to find SPR index adjustment
+ continue;
+ }
+
+ if( !g_sprRegister[l_sprBitPos - l_sprIndexAdj].iv_isThreadScope )
+ {
+ continue;
+ }
+
+ //Initialize self save region with SPR save entry for each thread
+ //level SPR
+ l_rc = initSelfSaveEntry( l_pSaveStart,
+ g_sprRegister[l_sprBitPos - l_sprIndexAdj].iv_saveMaskPos );
+
+ if( l_rc )
+ {
+ MY_ERR( "Failed to init thread self-save region for core %d thread %d",
+ i_corePos, l_threadPos );
+ break;
+ }
+
+ l_pSaveStart++;
+ l_pSaveStart++;
+ l_pSaveStart++;
+ }
+
+ }// for thread = 0;
+
+ if( l_rc )
+ {
+ //breakout if saw an error while init of thread SPR region
+ break;
+ }
+
+ l_pSaveStart =
+ (uint32_t*)&l_pHomer->iv_coreThreadRestore[i_corePos].iv_coreSaveArea[0];
+
+ *l_pSaveStart = SWIZZLE_4_BYTE(MFLR_R30);
+ l_pSaveStart++;
+
+ for( l_sprBitPos = 0; l_sprBitPos <= MAX_SPR_BIT_POS; l_sprBitPos++ )
+ {
+ l_rc = getSprRegIndexAdjustment( l_sprBitPos, &l_sprIndexAdj );
+
+ if( STOP_SAVE_SPR_BIT_POS_RESERVE == l_rc )
+ {
+ //Failed to find SPR index adjustment
+ continue;
+ }
+
+ if( g_sprRegister[l_sprBitPos - l_sprIndexAdj].iv_isThreadScope )
+ {
+ continue;
+ }
+
+ //Initialize self save region with SPR save entry for each core
+ //level SPR
+ l_rc = initSelfSaveEntry( l_pSaveStart,
+ g_sprRegister[l_sprBitPos - l_sprIndexAdj].iv_saveMaskPos );
+
+ if( l_rc )
+ {
+ MY_ERR( "Failed to init core self-save region for core %d thread %d",
+ i_corePos, l_threadPos );
+ break;
+ }
+
+ l_pSaveStart++;
+ l_pSaveStart++;
+ l_pSaveStart++;
+ }
+ }
+ while(0);
+
+ MY_INF( "<< p9_stop_init_self_save" );
+ return l_rc;
+}
+
+#ifdef __cplusplus
+} //namespace stopImageSection ends
+
+} //extern "C"
+#endif
diff --git a/roms/skiboot/libpore/p9_stop_api.H b/roms/skiboot/libpore/p9_stop_api.H
new file mode 100644
index 000000000..17caedb3c
--- /dev/null
+++ b/roms/skiboot/libpore/p9_stop_api.H
@@ -0,0 +1,244 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p9/procedures/utils/stopreg/p9_stop_api.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015,2018 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __P9_STOP_IMAGE_API_
+#define __P9_STOP_IMAGE_API_
+
+#include <stdint.h>
+
+#ifdef __SKIBOOT__
+ #include <skiboot.h>
+#endif
+
+///
+/// @file p9_stop_api.H
+/// @brief describes STOP API which create/manipulate STOP image.
+///
+// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
+// *HWP Team : PM
+// *HWP Level : 2
+// *HWP Consumed by : HB:HYP
+
+#ifdef __cplusplus
+namespace stopImageSection
+{
+#endif
+
+/**
+ * @brief all SPRs and MSR for which register restore is to be supported.
+ * @note STOP API design has built in support to accomodate 8 register of
+ * scope core and thread each.
+ */
+typedef enum
+{
+ P9_STOP_SPR_DAWR = 180, // thread register
+ P9_STOP_SPR_CIABR = 187, // thread register
+ P9_STOP_SPR_DAWRX = 188, // thread register
+ P9_STOP_SPR_HSPRG0 = 304, // thread register
+ P9_STOP_SPR_HRMOR = 313, // core register
+ P9_STOP_SPR_LPCR = 318, // thread register
+ P9_STOP_SPR_HMEER = 337, // core register
+ P9_STOP_SPR_PTCR = 464, // core register
+ P9_STOP_SPR_USPRG0 = 496, // thread register
+ P9_STOP_SPR_USPRG1 = 497, // thread register
+ P9_STOP_SPR_URMOR = 505, // core register
+ P9_STOP_SPR_SMFCTRL = 511, // thread register
+ P9_STOP_SPR_LDBAR = 850, // thread register
+ P9_STOP_SPR_PSSCR = 855, // thread register
+ P9_STOP_SPR_PMCR = 884, // core register
+ P9_STOP_SPR_HID = 1008, // core register
+ P9_STOP_SPR_MSR = 2000, // thread register
+} CpuReg_t;
+
+/**
+ * @brief lists all the bad error codes.
+ */
+typedef enum
+{
+ STOP_SAVE_SUCCESS = 0,
+ STOP_SAVE_ARG_INVALID_IMG = 1,
+ STOP_SAVE_ARG_INVALID_REG = 2,
+ STOP_SAVE_ARG_INVALID_THREAD = 3,
+ STOP_SAVE_ARG_INVALID_MODE = 4,
+ STOP_SAVE_ARG_INVALID_CORE = 5,
+ STOP_SAVE_SPR_ENTRY_NOT_FOUND = 6,
+ STOP_SAVE_SPR_ENTRY_UPDATE_FAILED = 7,
+ STOP_SAVE_SCOM_INVALID_OPERATION = 8,
+ STOP_SAVE_SCOM_INVALID_SECTION = 9,
+ STOP_SAVE_SCOM_INVALID_ADDRESS = 10,
+ STOP_SAVE_SCOM_INVALID_CHIPLET = 11,
+ STOP_SAVE_SCOM_ENTRY_UPDATE_FAILED = 12,
+ STOP_SAVE_INVALID_FUSED_CORE_STATUS = 13,
+ STOP_SAVE_FAIL = 14, // for internal failure within firmware.
+ STOP_SAVE_SPR_ENTRY_MISSING = 15,
+ STOP_SAVE_SPR_BIT_POS_RESERVE = 16,
+} StopReturnCode_t;
+
+/**
+ * @brief summarizes all operations supported on scom entries of STOP image.
+ */
+typedef enum
+{
+ P9_STOP_SCOM_OP_MIN = 0,
+ P9_STOP_SCOM_APPEND = 1,
+ P9_STOP_SCOM_REPLACE = 2,
+ P9_STOP_SCOM_OR = 3,
+ P9_STOP_SCOM_AND = 4,
+ P9_STOP_SCOM_NOOP = 5,
+ P9_STOP_SCOM_RESET = 6,
+ P9_STOP_SCOM_OR_APPEND = 7,
+ P9_STOP_SCOM_AND_APPEND = 8,
+ P9_STOP_SCOM_OP_MAX = 9
+} ScomOperation_t;
+
+/**
+ * @brief All subsections that contain scom entries in a STOP image.
+ */
+typedef enum
+{
+ P9_STOP_SECTION_MIN = 0,
+ P9_STOP_SECTION_CORE_SCOM = 1,
+ P9_STOP_SECTION_EQ_SCOM = 2,
+ P9_STOP_SECTION_L2 = 3,
+ P9_STOP_SECTION_L3 = 4,
+ P9_STOP_SECTION_MAX = 5
+} ScomSection_t;
+
+/**
+ * @brief versions pertaining relvant to STOP API.
+ */
+typedef enum
+{
+ STOP_API_VER = 0x00,
+ STOP_API_VER_CONTROL = 0x02,
+} VersionList_t;
+
+/**
+ * @brief Summarizes bit position allocated to SPRs in save bit mask vector.
+ */
+typedef enum
+{
+ BIT_POS_CIABR = 0,
+ BIT_POS_DAWR = 1,
+ BIT_POS_DAWRX = 2,
+ BIT_POS_HSPRG0 = 3,
+ BIT_POS_LDBAR = 4,
+ BIT_POS_LPCR = 5,
+ BIT_POS_PSSCR = 6,
+ BIT_POS_MSR = 7,
+ BIT_POS_HRMOR = 20,
+ BIT_POS_HID = 21,
+ BIT_POS_HMEER = 22,
+ BIT_POS_PMCR = 23,
+ BIT_POS_PTCR = 24,
+ BIT_POS_SMFCTRL = 28,
+ BIT_POS_USPRG0 = 29,
+ BIT_POS_USPRG1 = 30,
+ BIT_POS_URMOR = 31,
+} SprBitPositionList_t;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**
+ * @brief Updates STOP image entry associated with CPU register.
+ * @param[in] i_pImage start address of homer image associated with processor.
+ * @param[in] i_regId id of SPR for which STOP image needs to be updated.
+ * @param[in] i_regData data to be restored in SPR register.
+ * @param[in] i_pir value of processor identification register (PIR)
+ * @return STOP_SAVE_SUCCESS SUCCESS if image is updated successfully, error
+ * code otherwise.
+ */
+
+StopReturnCode_t p9_stop_save_cpureg( void* const i_pImage,
+ const CpuReg_t i_regId,
+ const uint64_t i_regData,
+ const uint64_t i_pir );
+/**
+ * @brief Updates STOP image entry associated with CPU register.
+ * @param[in] i_pImage start address of homer image associated with processor.
+ * @param[in] i_corePos physical core's relative position within processor chip.
+ * @return STOP_SAVE_SUCCESS SUCCESS if image is initialized successfully, error
+ * code otherwise.
+ * @note API is intended only for use case of HOMER build. There is no explicit
+ * effort to support any other use case.
+ *
+ */
+
+StopReturnCode_t p9_stop_init_cpureg( void* const i_pImage, const uint32_t i_corePos );
+
+/**
+ * @brief Updates scom image entry associated with given core or cache in
+ * STOP section of homer image.
+ * @param[in] i_pImage start address of homer image of P9 chip.
+ * @param[in] i_scomAddress fully qualified address of SCOM register.
+ * @param[in] i_scomData data associated with SCOM register.
+ * @param[in] i_operation operation to be done on SCOM image entry.
+ * @param[in] i_section area to which given SCOM entry belongs.
+ * @return STOP_SAVE_SUCCESS if image is updated successfully, error code
+ * otherwise.
+ * @note API is intended to update SCOM image entry associated with given
+ * core or given part of a cache section. API doesn't validate if
+ * a given SCOM address really belongs to given section.
+ */
+StopReturnCode_t p9_stop_save_scom( void* const i_pImage,
+ const uint32_t i_scomAddress,
+ const uint64_t i_scomData,
+ const ScomOperation_t i_operation,
+ const ScomSection_t i_section );
+
+/**
+ * @brief Facilitates self save and restore of a list of SPRs of a thread.
+ * @param[in] i_pImage points to the start of HOMER image of P9 chip.
+ * @param[in] i_pir PIR associated with thread
+ * @param[in] i_saveRegVector bit vector representing SPRs that needs to be restored.
+ * @return STOP_SAVE_SUCCESS if API succeeds, error code otherwise.
+ * @note SPR save vector is a bit vector. For each SPR supported,
+ * there is an associated bit position in the bit vector.Refer
+ * to definition of SprBitPositionList_t to determine bit position
+ * associated with a particular SPR.
+ */
+StopReturnCode_t
+p9_stop_save_cpureg_control( void* i_pImage, const uint64_t i_pir,
+ const uint32_t i_saveRegVector );
+
+/**
+ * @brief initializes self-save region with specific instruction.
+ * @param[in] i_pImage start address of homer image of P9 chip.
+ * @param[in] i_corePos physical core's relative position within processor chip.
+ * @return STOP_SAVE_SUCCESS SUCCESS if self-save is initialized successfully,
+ * error code otherwise.
+ * @note API is intended only for use case of HOMER build. There is no explicit
+ * effort to support any other use case.
+ */
+StopReturnCode_t p9_stop_init_self_save( void* const i_pImage, const uint32_t i_corePos );
+
+#ifdef __cplusplus
+} // extern "C"
+}; // namespace stopImageSection ends
+#endif //__cplusplus
+
+#endif //__P9_STOP_IMAGE_API_
diff --git a/roms/skiboot/libpore/p9_stop_data_struct.H b/roms/skiboot/libpore/p9_stop_data_struct.H
new file mode 100644
index 000000000..1e9721e01
--- /dev/null
+++ b/roms/skiboot/libpore/p9_stop_data_struct.H
@@ -0,0 +1,202 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p9/procedures/utils/stopreg/p9_stop_data_struct.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015,2018 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file p9_stop_data_struct.H
+/// @brief describes data structures internal to STOP API.
+///
+// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
+// *HWP Team : PM
+// *HWP Level : 2
+// *HWP Consumed by : HB:HYP
+#ifndef __STOP_DATA_STRUCT_
+#define __STOP_DATA_STRUCT_
+
+#include "p9_hcd_memmap_base.H"
+
+#ifdef __SKIBOOT__
+ #include <skiboot.h>
+#endif
+
+#ifdef __FAPI_2_
+ #include <fapi2.H>
+#endif
+
+#ifdef PPC_HYP
+
+ #define STATIC
+
+#else
+
+ #define STATIC static
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+namespace stopImageSection
+{
+#endif
+
+enum
+{
+ MAX_SPR_RESTORE_INST = 0x08,
+ SIZE_PER_SPR_RESTORE_INST = ((4 * sizeof(uint8_t)) / sizeof(uint32_t)),
+ MAX_THREAD_LEVEL_SPRS = 11,
+ MAX_CORE_LEVEL_SPRS = 6,
+ MAX_SPR_BIT_POS = 31,
+ SPR_BIT_POS_8 = 8,
+ SPR_BIT_POS_19 = 19,
+ SPR_BIT_POS_25 = 25,
+ SPR_BIT_POS_27 = 27,
+};
+
+enum SprEntryUpdateMode
+{
+ INIT_SPR_REGION = 0x01,
+ UPDATE_SPR_ENTRY = 0x02,
+};
+
+typedef struct
+{
+ uint32_t scomEntryHeader;
+ uint32_t scomEntryAddress;
+ uint64_t scomEntryData;
+} ScomEntry_t;
+
+/**
+ * @brief models a CPU register restoration area in STOP section of homer image.
+ */
+typedef struct
+{
+ uint8_t iv_threadRestoreArea[MAX_THREADS_PER_CORE][SMF_CORE_RESTORE_THREAD_AREA_SIZE];
+ uint8_t iv_threadSaveArea[MAX_THREADS_PER_CORE][SMF_SELF_SAVE_THREAD_AREA_SIZE];
+ uint8_t iv_coreRestoreArea[SMF_CORE_RESTORE_CORE_AREA_SIZE];
+ uint8_t iv_coreSaveArea[SMF_CORE_SAVE_CORE_AREA_SIZE];
+} SmfSprRestoreArea_t;
+
+typedef struct
+{
+ uint8_t iv_threadArea[CORE_RESTORE_THREAD_AREA_SIZE];
+ uint8_t iv_coreArea[CORE_RESTORE_CORE_AREA_SIZE];
+} SprRestoreArea_t;
+
+/**
+ * @brief models homer image of a chip.
+ * @note sections not relevant for CPU register restoration have been
+ * abstracted using field 'reserve'.
+ */
+typedef struct
+{
+ uint8_t iv_occ_host_sgpe_area[ TWO_MB ]; // CPU restore area starts at an offset of 2MB from chip HOMER
+ uint8_t iv_interrruptHandler[SELF_RESTORE_INT_SIZE];
+ uint8_t iv_threadLauncher[THREAD_LAUNCHER_SIZE];
+ SprRestoreArea_t iv_coreThreadRestore[MAX_CORES_PER_CHIP][MAX_THREADS_PER_CORE];
+ uint8_t reserve[(ONE_KB * ONE_KB) - SELF_RESTORE_SIZE_TOTAL];
+} HomerSection_t;
+
+
+/**
+ * @brief models homer image of a chip that supports SMF.
+ * @note sections not relevant for CPU register restoration have been
+ * abstracted using field 'reserve'.
+ */
+typedef struct
+{
+ uint8_t iv_occ_host_sgpe_area[ TWO_MB ];
+ uint8_t iv_interrruptHandler[SELF_RESTORE_INT_SIZE];
+ uint8_t iv_threadLauncher[SMF_THREAD_LAUNCHER_SIZE];
+ SmfSprRestoreArea_t iv_coreThreadRestore[MAX_CORES_PER_CHIP];
+ uint8_t reserve[(ONE_KB * ONE_KB) - SMF_SELF_RESTORE_SIZE_TOTAL];
+} SmfHomerSection_t;
+
+/**
+ * @brief models cache subsection in STOP section of a given homer image.
+ * @note given the start of cache subsection associated with a given core,
+ * the structure below represents what a cache subsection would look
+ * like. Based on known start address, quick traversing can be done
+ * within the cache subsection.
+ */
+typedef struct
+{
+ ScomEntry_t nonCacheArea[MAX_EQ_SCOM_ENTRIES];
+ ScomEntry_t l2CacheArea[MAX_L2_SCOM_ENTRIES];
+ ScomEntry_t l3CacheArea[MAX_L3_SCOM_ENTRIES];
+} StopCacheSection_t;
+
+/**
+ * @brief summarizes attributes associated with a SPR register.
+ */
+typedef struct
+{
+ uint32_t iv_sprId;
+ bool iv_isThreadScope;
+ uint32_t iv_saveMaskPos;
+
+} StopSprReg_t;
+
+enum
+{
+ SIZE_SCOM_ENTRY = sizeof( ScomEntry_t ),
+ SCOM_ENTRY_START = 0xDEADDEAD,
+ BAD_SAVE_MASK = 0x007FF000,
+ MAX_SPR_INDEX = 31,
+ TEST_BIT_PATTERN = 0x80000000,
+};
+
+#ifdef __FAPI_2_
+ #define MY_ERR( _fmt_, _args_...) FAPI_ERR(_fmt_, ##_args_)
+ #define MY_INF(_fmt_, _args_...) FAPI_INF(_fmt_, ##_args_)
+#else
+ #define MY_ERR( _fmt_, _args_...)
+ #define MY_INF(_fmt_, _args_...)
+#endif
+
+#define CORE_ID_SCOM_START(io_image,\
+ i_chipletId) \
+((ScomEntry_t*)(((uint8_t*)(io_image)) + CORE_SCOM_RESTORE_HOMER_OFFSET +\
+ ((i_chipletId - CORE_CHIPLET_ID_MIN) * \
+ CORE_SCOM_RESTORE_SIZE_PER_CORE)));
+
+#define CACHE_SECTN_START(io_image,\
+ i_chipletId) \
+((StopCacheSection_t *)(((uint8_t *)(io_image)) + QUAD_SCOM_RESTORE_HOMER_OFFSET +\
+ ((i_chipletId - CACHE_CHIPLET_ID_MIN) * \
+ QUAD_SCOM_RESTORE_SIZE_PER_QUAD)));
+
+#define CACHE_SCOM_ADDR(io_image,\
+ i_chipletId,\
+ i_maxScomEntry)\
+((ScomEntry_t *)(((uint8_t *)(io_image)) + QUAD_SCOM_RESTORE_HOMER_OFFSET +\
+ ((i_chipletId - CACHE_CHIPLET_ID_MIN) * \
+ ((i_maxScomEntry + 1) * 16 ))));
+#ifdef __cplusplus
+} // extern "C"
+
+} //namespace stopImageSection ends
+#endif //__cplusplus
+
+#endif
diff --git a/roms/skiboot/libpore/p9_stop_util.C b/roms/skiboot/libpore/p9_stop_util.C
new file mode 100644
index 000000000..950198849
--- /dev/null
+++ b/roms/skiboot/libpore/p9_stop_util.C
@@ -0,0 +1,193 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p9/procedures/utils/stopreg/p9_stop_util.C $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2015,2018 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+
+///
+/// @file p9_stop_util.C
+/// @brief implements some utilty functions for STOP API.
+///
+// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
+// *HWP Team : PM
+// *HWP Level : 2
+// *HWP Consumed by : HB:HYP
+#ifdef PPC_HYP
+ #include <HvPlicModule.H>
+#endif
+
+#include "p9_stop_api.H"
+#include "p9_stop_util.H"
+#include "p9_stop_data_struct.H"
+
+#ifdef __cplusplus
+namespace stopImageSection
+{
+#endif
+
+//-----------------------------------------------------------------------
+
+/**
+ * @brief Returns proc chip's fuse mode status.
+ * @param i_pImage points to start of chip's HOMER image.
+ * @param o_fusedMode points to fuse mode information.
+ * @return STOP_SAVE_SUCCESS if functions succeeds, error code otherwise.
+ */
+STATIC StopReturnCode_t isFusedMode( void* const i_pImage, bool* o_fusedMode )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+ uint64_t cpmrCheckWord = 0;
+ *o_fusedMode = false;
+
+ do
+ {
+ HomerSection_t* pHomerDesc = ( HomerSection_t* ) i_pImage;
+ HomerImgDesc_t* pHomer = (HomerImgDesc_t*)( pHomerDesc->iv_interrruptHandler );
+
+ if( !i_pImage )
+ {
+ MY_ERR( "invalid pointer to HOMER image");
+ l_rc = STOP_SAVE_ARG_INVALID_IMG;
+ break;
+ }
+
+
+ cpmrCheckWord = SWIZZLE_8_BYTE(pHomer->cpmrMagicWord);
+ cpmrCheckWord = cpmrCheckWord >> 32;
+
+ if( CPMR_REGION_CHECK_WORD != cpmrCheckWord )
+ {
+ MY_ERR("corrupt or invalid HOMER image location 0x%016llx",
+ SWIZZLE_8_BYTE(pHomer->cpmrMagicWord) );
+ l_rc = STOP_SAVE_ARG_INVALID_IMG;
+ break;
+ }
+
+ if( (uint8_t) FUSED_CORE_MODE == pHomer->fusedModeStatus )
+ {
+ *o_fusedMode = true;
+ break;
+ }
+
+ if( (uint8_t) NONFUSED_CORE_MODE == pHomer->fusedModeStatus )
+ {
+ break;
+ }
+
+ MY_ERR("Unexpected value 0x%08x for fused mode. Bad or corrupt "
+ "HOMER location", pHomer->fusedModeStatus );
+ l_rc = STOP_SAVE_INVALID_FUSED_CORE_STATUS ;
+
+ }
+ while(0);
+
+ return l_rc;
+}
+
+//----------------------------------------------------------------------
+
+StopReturnCode_t getCoreAndThread( void* const i_pImage, const uint64_t i_pir,
+ uint32_t* o_pCoreId, uint32_t* o_pThreadId )
+{
+ StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
+
+ do
+ {
+ // for SPR restore using 'Virtual Thread' and 'Physical Core' number
+ // In Fused Mode:
+ // bit b28 and b31 of PIR give physical core and b29 and b30 gives
+ // virtual thread id.
+ // In Non Fused Mode
+ // bit 28 and b29 of PIR give both logical and physical core number
+ // whereas b30 and b31 gives logical and virtual thread id.
+ bool fusedMode = false;
+ uint8_t coreThreadInfo = (uint8_t)i_pir;
+ *o_pCoreId = 0;
+ *o_pThreadId = 0;
+ l_rc = isFusedMode( i_pImage, &fusedMode );
+
+ if( l_rc )
+ {
+ MY_ERR(" Checking Fused mode. Read failed 0x%08x", l_rc );
+ break;
+ }
+
+ if( fusedMode )
+ {
+ if( coreThreadInfo & FUSED_CORE_BIT1 )
+ {
+ *o_pThreadId = 2;
+ }
+
+ if( coreThreadInfo & FUSED_CORE_BIT2 )
+ {
+ *o_pThreadId += 1;
+ }
+
+ if( coreThreadInfo & FUSED_CORE_BIT0 )
+ {
+ *o_pCoreId = 2;
+ }
+
+ if( coreThreadInfo & FUSED_CORE_BIT3 )
+ {
+ *o_pCoreId += 1;
+ }
+ }
+ else
+ {
+ if( coreThreadInfo & FUSED_CORE_BIT0 )
+ {
+ *o_pCoreId = 2;
+ }
+
+ if ( coreThreadInfo & FUSED_CORE_BIT1 )
+ {
+ *o_pCoreId += 1;
+ }
+
+ if( coreThreadInfo & FUSED_CORE_BIT2 )
+ {
+ *o_pThreadId = 2;
+ }
+
+ if( coreThreadInfo & FUSED_CORE_BIT3 )
+ {
+ *o_pThreadId += 1;
+ }
+ }
+
+
+ MY_INF("Core Type %s", fusedMode ? "Fused" : "Un-Fused" );
+ //quad field is not affected by fuse mode
+ *o_pCoreId += 4 * (( coreThreadInfo & 0x70 ) >> 4 );
+ }
+ while(0);
+
+ return l_rc;
+}
+
+#ifdef __cplusplus
+}//namespace stopImageSection ends
+#endif
+
diff --git a/roms/skiboot/libpore/p9_stop_util.H b/roms/skiboot/libpore/p9_stop_util.H
new file mode 100644
index 000000000..3266fdefe
--- /dev/null
+++ b/roms/skiboot/libpore/p9_stop_util.H
@@ -0,0 +1,145 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/import/chips/p9/procedures/hwp/lib/p9_stop_util.H $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2016,2017 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __P9_STOP_UTIL_
+#define __P9_STOP_UTIL_
+
+#ifdef _AIX
+ #define __BYTE_ORDER __BIG_ENDIAN
+#elif __SKIBOOT__
+ #include <skiboot.h>
+#else
+ #include <endian.h>
+#endif
+
+#ifndef __PPE_PLAT
+ #include "p9_stop_api.H"
+#endif
+
+#ifdef FAPI_2
+ #include <fapi2.H>
+#endif
+
+///
+/// @file p9_stop_util.H
+/// @brief describes some utilty functions for STOP API.
+///
+// *HWP HW Owner : Greg Still <stillgs@us.ibm.com>
+// *HWP FW Owner : Prem Shanker Jha <premjha2@in.ibm.com>
+// *HWP Team : PM
+// *HWP Level : 2
+// *HWP Consumed by : HB:HYP
+#ifndef __PPE_PLAT
+#ifdef __cplusplus
+namespace stopImageSection
+{
+#endif
+#endif //__PPE_PLAT
+/**
+ * @brief helper function to swizzle given input data
+ * @note swizles bytes to handle endianess issue.
+ */
+#if( __BYTE_ORDER == __BIG_ENDIAN )
+
+// NOP if it is a big endian system
+#define SWIZZLE_2_BYTE(WORD) WORD
+#define SWIZZLE_4_BYTE(WORD) WORD
+#define SWIZZLE_8_BYTE(WORD) WORD
+
+#else
+#define SWIZZLE_2_BYTE(WORD) \
+ ( (((WORD) >> 8) & 0x00FF) | (((WORD) << 8) & 0xFF00) )
+
+#define SWIZZLE_4_BYTE(WORD) \
+ ( (((WORD) >> 24) & 0x000000FF) | (((WORD) >> 8) & 0x0000FF00) | \
+ (((WORD) << 8) & 0x00FF0000) | (((WORD) << 24) & 0xFF000000) )
+
+#define SWIZZLE_8_BYTE(WORD) \
+ ( (((WORD) >> 56) & 0x00000000000000FF) | \
+ (((WORD) >> 40) & 0x000000000000FF00)| \
+ (((WORD) >> 24) & 0x0000000000FF0000) | \
+ (((WORD) >> 8) & 0x00000000FF000000) | \
+ (((WORD) << 8) & 0x000000FF00000000) | \
+ (((WORD) << 24) & 0x0000FF0000000000) | \
+ (((WORD) << 40) & 0x00FF000000000000) | \
+ (((WORD) << 56) & 0xFF00000000000000) )
+#endif
+
+/**
+ * @brief describes details of CPMR header in HOMER.
+ */
+typedef struct
+{
+ uint64_t attnOpcodes;
+ uint64_t cpmrMagicWord;
+ uint32_t buildDate;
+ uint32_t version;
+ uint8_t reserve1[7];
+ uint8_t fusedModeStatus;
+ uint32_t cmeImgOffset;
+ uint32_t cmeImgLength;
+ uint32_t cmeCommonRingOffset;
+ uint32_t cmeCommonRingLength;
+ uint32_t cmePstateOffset;
+ uint32_t cmePstateLength;
+ uint32_t coreSpecRingOffset;
+ uint32_t coreSpecRingLen;
+ uint32_t coreScomOffset;
+ uint32_t coreScomLength;
+ uint32_t reserve2[184];
+} HomerImgDesc_t;
+
+/**
+ * @brief enumerates bit(s) positions of interest for PIR.
+ */
+enum
+{
+ FUSED_CORE_BIT0 = 0x08,
+ FUSED_CORE_BIT1 = 0x04,
+ FUSED_CORE_BIT2 = 0x02,
+ FUSED_CORE_BIT3 = 0x01,
+ QUAD_BITS = 0x70
+};
+
+#ifndef __PPE_PLAT
+/**
+ * @brief returns core id and thread id by parsing a given PIR.
+ * @param i_pStopImage points to STOP image associated with a proc chip.
+ * @param i_pir PIR associated with a core's thread.
+ * @param o_coreId points to core id value obtained from PIR.
+ * @param o_threadId points to thread id value obtained from PIR.
+ * @return SUCCESS if function suceeds, error code otherwise.
+ */
+StopReturnCode_t getCoreAndThread( void* const i_pStopImage,
+ const uint64_t i_pir,
+ uint32_t* o_coreId,
+ uint32_t* o_threadId );
+#ifdef __cplusplus
+} // namespace stopImageSection ends
+
+#endif
+#endif //__PPE_PLAT
+#endif
+
+
diff --git a/roms/skiboot/libpore/pgas.h b/roms/skiboot/libpore/pgas.h
new file mode 100644
index 000000000..5d1dbf384
--- /dev/null
+++ b/roms/skiboot/libpore/pgas.h
@@ -0,0 +1,1169 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/hwpf/hwp/build_winkle_images/p8_slw_build/pgas.h $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012,2014 */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __PGAS_H__
+#define __PGAS_H__
+
+#define __PGAS__
+
+// $Id: pgas.h,v 1.21 2013/11/20 14:06:39 bcbrock Exp $
+
+// ** WARNING : This file is maintained as part of the OCC firmware. Do **
+// ** not edit this file in the PMX area, the hardware procedure area, **
+// ** or the PoreVe area as any changes will be lost. **
+
+/// \file pgas.h
+/// \brief Pore GAS
+///
+/// PGAS is documented in a separate standalone document entitled <em> PGAS :
+/// PORE GAS (GNU Assembler) User's and Reference Manual </em>.
+///
+/// This file defines support macros for the GNU PORE assembler, and the PORE
+/// inline assembler and disassebler which follow the PGAS assembly syntax.
+/// If the compile swith PGAS_PPC is defined in the environment then pgas.h
+/// includes pgas_ppc.h which transforms a PowerPC assembler into an assembler
+/// for PORE.
+
+// These are the opcodes and mnemonics as defined by the PORE hardware
+// manual. Many of them will change names slightly in PGAS.
+
+#define PORE_OPCODE_NOP 0x0f
+#define PORE_OPCODE_WAIT 0x01
+#define PORE_OPCODE_TRAP 0x02
+#define PORE_OPCODE_HOOK 0x4f
+
+#define PORE_OPCODE_BRA 0x10
+#define PORE_OPCODE_BRAZ 0x12
+#define PORE_OPCODE_BRANZ 0x13
+#define PORE_OPCODE_BRAI 0x51
+#define PORE_OPCODE_BSR 0x14
+#define PORE_OPCODE_BRAD 0x1c
+#define PORE_OPCODE_BSRD 0x1d
+#define PORE_OPCODE_RET 0x15
+#define PORE_OPCODE_CMPBRA 0x56
+#define PORE_OPCODE_CMPNBRA 0x57
+#define PORE_OPCODE_CMPBSR 0x58
+#define PORE_OPCODE_LOOP 0x1f
+
+#define PORE_OPCODE_ANDI 0x60
+#define PORE_OPCODE_ORI 0x61
+#define PORE_OPCODE_XORI 0x62
+
+#define PORE_OPCODE_AND 0x25
+#define PORE_OPCODE_OR 0x26
+#define PORE_OPCODE_XOR 0x27
+
+#define PORE_OPCODE_ADD 0x23
+#define PORE_OPCODE_ADDI 0x24
+#define PORE_OPCODE_SUB 0x29
+#define PORE_OPCODE_SUBI 0x28
+#define PORE_OPCODE_NEG 0x2a
+
+#define PORE_OPCODE_COPY 0x2c
+#define PORE_OPCODE_ROL 0x2e
+
+#define PORE_OPCODE_LOAD20 0x30
+#define PORE_OPCODE_LOAD64 0x71
+#define PORE_OPCODE_SCR1RD 0x32
+#define PORE_OPCODE_SCR1RDA 0x73
+#define PORE_OPCODE_SCR2RD 0x36
+#define PORE_OPCODE_SCR2RDA 0x77
+#define PORE_OPCODE_WRI 0x78
+#define PORE_OPCODE_BS 0x74
+#define PORE_OPCODE_BC 0x75
+#define PORE_OPCODE_SCR1WR 0x39
+#define PORE_OPCODE_SCR2WR 0x3a
+#define PORE_OPCODE_SCAND 0x7c
+
+
+// These are the PGAS versions of the PORE opcodes used in the legacy PGAS_PPC
+// assembler and the current PORE inline assembler/disassembler.
+
+#define PGAS_OPCODE_NOP PORE_OPCODE_NOP
+#define PGAS_OPCODE_WAITS PORE_OPCODE_WAIT
+#define PGAS_OPCODE_TRAP PORE_OPCODE_TRAP
+#define PGAS_OPCODE_HOOKI PORE_OPCODE_HOOK
+
+#define PGAS_OPCODE_BRA PORE_OPCODE_BRA
+#define PGAS_OPCODE_BRAZ PORE_OPCODE_BRAZ
+#define PGAS_OPCODE_BRANZ PORE_OPCODE_BRANZ
+#define PGAS_OPCODE_BRAI PORE_OPCODE_BRAI
+#define PGAS_OPCODE_BSR PORE_OPCODE_BSR
+#define PGAS_OPCODE_BRAD PORE_OPCODE_BRAD
+#define PGAS_OPCODE_BSRD PORE_OPCODE_BSRD
+#define PGAS_OPCODE_RET PORE_OPCODE_RET
+#define PGAS_OPCODE_CMPIBRAEQ PORE_OPCODE_CMPBRA
+#define PGAS_OPCODE_CMPIBRANE PORE_OPCODE_CMPNBRA
+#define PGAS_OPCODE_CMPIBSREQ PORE_OPCODE_CMPBSR
+#define PGAS_OPCODE_LOOP PORE_OPCODE_LOOP
+
+#define PGAS_OPCODE_ANDI PORE_OPCODE_ANDI
+#define PGAS_OPCODE_ORI PORE_OPCODE_ORI
+#define PGAS_OPCODE_XORI PORE_OPCODE_XORI
+
+#define PGAS_OPCODE_AND PORE_OPCODE_AND
+#define PGAS_OPCODE_OR PORE_OPCODE_OR
+#define PGAS_OPCODE_XOR PORE_OPCODE_XOR
+
+#define PGAS_OPCODE_ADD PORE_OPCODE_ADD
+#define PGAS_OPCODE_ADDS PORE_OPCODE_ADDI
+#define PGAS_OPCODE_SUB PORE_OPCODE_SUB
+#define PGAS_OPCODE_SUBS PORE_OPCODE_SUBI
+#define PGAS_OPCODE_NEG PORE_OPCODE_NEG
+
+#define PGAS_OPCODE_MR PORE_OPCODE_COPY
+#define PGAS_OPCODE_ROLS PORE_OPCODE_ROL
+
+#define PGAS_OPCODE_LS PORE_OPCODE_LOAD20
+#define PGAS_OPCODE_LI PORE_OPCODE_LOAD64
+#define PGAS_OPCODE_LD0 PORE_OPCODE_SCR1RD /* Used by LD */
+#define PGAS_OPCODE_LD0ANDI PORE_OPCODE_SCR1RDA /* Used by LDANDI */
+#define PGAS_OPCODE_LD1 PORE_OPCODE_SCR2RD /* Used by LD */
+#define PGAS_OPCODE_LD1ANDI PORE_OPCODE_SCR2RDA /* Used by LDANDI */
+#define PGAS_OPCODE_STI PORE_OPCODE_WRI
+#define PGAS_OPCODE_STD0 PORE_OPCODE_SCR1WR /* Used by STD */
+#define PGAS_OPCODE_STD1 PORE_OPCODE_SCR2WR /* Used by STD */
+#define PGAS_OPCODE_SCAND PORE_OPCODE_SCAND
+
+#ifdef IGNORE_HW274735
+
+// BSI and BCI are normally redacted due to HW274735. See also pgas.h
+
+#define PGAS_OPCODE_BSI PORE_OPCODE_BS
+#define PGAS_OPCODE_BCI PORE_OPCODE_BC
+
+#endif // IGNORE_HW274735
+
+// These are the programmer-visible register names as defined by the PORE
+// hardware manual. All of these names (except the PC) appear differently in
+// the PGAS syntax, in some cases to reduce confusion, in other cases just to
+// have more traditional short mnemonics.
+
+#define PORE_REGISTER_PRV_BASE_ADDR0 0x0
+#define PORE_REGISTER_PRV_BASE_ADDR1 0x1
+#define PORE_REGISTER_OCI_BASE_ADDR0 0x2
+#define PORE_REGISTER_OCI_BASE_ADDR1 0x3
+#define PORE_REGISTER_SCRATCH0 0x4
+#define PORE_REGISTER_SCRATCH1 0x5
+#define PORE_REGISTER_SCRATCH2 0x6
+#define PORE_REGISTER_ERROR_MASK 0x7
+#define PORE_REGISTER_EXE_TRIGGER 0x9
+#define PORE_REGISTER_DATA0 0xa
+#define PORE_REGISTER_PC 0xe
+#define PORE_REGISTER_IBUF_ID 0xf
+
+
+// PgP IBUF_ID values
+
+#define PORE_ID_GPE0 0x00
+#define PORE_ID_GPE1 0x01
+#define PORE_ID_SLW 0x08
+#define PORE_ID_SBE 0x04
+
+
+// Condition Codes
+
+#define PORE_CC_UGT 0x8000
+#define PORE_CC_ULT 0x4000
+#define PORE_CC_SGT 0x2000
+#define PORE_CC_SLT 0x1000
+#define PORE_CC_C 0x0800
+#define PORE_CC_V 0x0400
+#define PORE_CC_N 0x0200
+#define PORE_CC_Z 0x0100
+
+
+// Memory Spaces
+
+#define PORE_SPACE_UNDEFINED 0xffff
+#define PORE_SPACE_OCI 0x8000
+#define PORE_SPACE_PNOR 0x800b
+#define PORE_SPACE_OTPROM 0x0001
+#define PORE_SPACE_SEEPROM 0x800c
+#define PORE_SPACE_PIBMEM 0x0008
+
+
+#ifdef __ASSEMBLER__
+
+////////////////////////////////////////////////////////////////////////////
+// PGAS Base Assembler Support
+////////////////////////////////////////////////////////////////////////////
+
+
+ //////////////////////////////////////////////////////////////////////
+ // Condition Codes
+ //////////////////////////////////////////////////////////////////////
+
+ .set CC_UGT, PORE_CC_UGT
+ .set CC_ULT, PORE_CC_ULT
+ .set CC_SGT, PORE_CC_SGT
+ .set CC_SLT, PORE_CC_SLT
+ .set CC_C, PORE_CC_C
+ .set CC_V, PORE_CC_V
+ .set CC_N, PORE_CC_N
+ .set CC_Z, PORE_CC_Z
+
+
+ //////////////////////////////////////////////////////////////////////
+ // Utility Macros
+ //////////////////////////////////////////////////////////////////////
+
+ // 'Undefine' PowerPC mnemonics to trap programming errors
+
+ .macro ..undefppc1, i
+ .ifnc \i, ignore
+ .macro \i, args:vararg
+ .error "This is a PowerPC opcode - NOT a PGAS opcode or extended mnemonic"
+ .endm
+ .endif
+ .endm
+
+ .macro .undefppc, i0, i1=ignore, i2=ignore, i3=ignore
+ ..undefppc1 \i0
+ ..undefppc1 \i1
+ ..undefppc1 \i2
+ ..undefppc1 \i3
+ .endm
+
+
+ //////////////////////////////////////////////////////////////////////
+ // Argument Checking Macros
+ //////////////////////////////////////////////////////////////////////
+ //
+ // These macros remain in the final pgas.h file because 1) they are
+ // required for some PGAS pseudo-ops, and 2) to support robust
+ // assembler macro definitions.
+
+ // Check an unsigned immediate for size
+
+ .macro ..checku, x:req, bits:req, err="Unsigned value too large"
+
+ .if (((\bits) <= 0) || ((\bits) > 63))
+ .error "The number of bits must be in the range 0 < bits < 64"
+ .endif
+
+ .iflt (\x)
+ .error "An unsigned value is required here"
+ .endif
+
+ .ifgt ((\x) - (0xffffffffffffffff >> (64 - (\bits))))
+ .error "\err"
+ .endif
+
+ .endm
+
+ // Check unsigned 16/22-bit immediates for size
+ //
+ // In general, PGAS can check immediate values for size restrictions,
+ // but unfortunately is not able to check address offset immediates for
+ // range.
+
+ .macro ..check_u16, u16
+ ..checku (\u16), 16, "Unsigned immediate is larger than 16 bits"
+ .endm
+
+ .macro ..check_u24, u24
+ ..checku (\u24), 24, "Unsigned immediate is larger than 24 bits"
+ .endm
+
+ // Check a 16/20/22-bit signed immediate for size
+
+ .macro ..check_s16, s16
+ .iflt \s16
+ .iflt \s16 + 0x8000
+ .error "Immediate value too small for a signed 16-bit field"
+ .endif
+ .else
+ .ifgt \s16 - 0x7fff
+ .error "Immediate value too large for a signed 16-bit field"
+ .endif
+ .endif
+ .endm
+
+ .macro ..check_s20, s20
+ .iflt \s20
+ .iflt \s20 + 0x80000
+ .error "Immediate value too small for a signed 20-bit field"
+ .endif
+ .else
+ .ifgt \s20 - 0x7ffff
+ .error "Immediate value too large for a signed 20-bit field"
+ .endif
+ .endif
+ .endm
+
+ .macro ..check_s22, s22
+ .iflt \s22
+ .iflt \s22 + 0x200000
+ .error "Immediate value too small for a signed 22-bit field"
+ .endif
+ .else
+ .ifgt \s22 - 0x1fffff
+ .error "Immediate value too large for a signed 22-bit field"
+ .endif
+ .endif
+ .endm
+
+ // Check a putative SCOM address for bits 0 and 8:11 == 0.
+
+ .macro ..check_scom, address
+ .if ((\address) & 0x80f00000)
+ .error "Valid SCOM addresses must have bits 0 and 8:11 equal to 0."
+ .endif
+ .endm
+
+ // A register required to be D0
+
+ .macro ..d0, reg
+ .if (\reg != D0)
+ .error "Data register D0 is required here"
+ .endif
+ .endm
+
+ // A register pair required to be D0, D1 in order
+
+ .macro ..d0d1, reg1, reg2
+ .if (((\reg1) != D0) && ((\reg2) != D1))
+ .error "Register-Register ALU operations are only defined on the source pair D0, D1"
+ .endif
+ .endm
+
+ // A register pair required to be D0, D1 in any order
+ .macro ..dxdy, reg1, reg2, err="Expecting D0, D1 in either order"
+ .if !((((\reg1) == D0) && ((\reg2) == D1)) || \
+ (((\reg1) == D1) && ((\reg2) == D0)))
+ .error "\err"
+ .endif
+ .endm
+
+ // A register pair required to be A0, A1 in any order
+ .macro ..axay, reg1, reg2, err="Expecting A0, A1 in either order"
+ .if !((((\reg1) == A0) && ((\reg2) == A1)) || \
+ (((\reg1) == A1) && ((\reg2) == A0)))
+ .error "\err"
+ .endif
+ .endm
+
+ // A register pair required to be the same register
+
+ .macro ..same, dest, src
+ .if ((\dest) != (\src))
+ .error "PGAS requires the src and dest register of ADDS/SUBS to be explicit and identical"
+ .endif
+ .endm
+
+ // A "Data" register
+
+ .macro ..data, reg:req, err="Expecting a 'Data' register"
+ .if (\reg != D0)
+ .if (\reg != D1)
+ .error "\err"
+ .endif
+ .endif
+ .endm
+
+ // An "Address" register
+
+ .macro ..address, reg:req, err=:"Expecting an 'Address' register"
+ .if (\reg != A0)
+ .if (\reg != A1)
+ .error "\err"
+ .endif
+ .endif
+ .endm
+
+ // A "Pervasive Chiplet ID" register
+
+ .macro ..pervasive_chiplet_id, reg:req, err="Expecting a 'Pervasive Chiplet ID' register"
+ .if (\reg != P0)
+ .if (\reg != P1)
+ .error "\err"
+ .endif
+ .endif
+ .endm
+
+ // A "Branch Compare Data" register
+
+ .macro ..branch_compare_data, reg
+ .if (\reg != D0)
+ .if (\reg != D1)
+ .if (\reg != CTR)
+ .error "Expecting a 'Branch Compare Data' register"
+ .endif
+ .endif
+ .endif
+ .endm
+
+ // An "LS Destination" register; Also the set for ADDS/SUBS
+
+ .macro ..ls_destination, reg
+ .if (\reg != D0)
+ .if (\reg != D1)
+ .if (\reg != A0)
+ .if (\reg != A1)
+ .if (\reg != P0)
+ .if (\reg != P1)
+ .if (\reg != CTR)
+ .error "Expecting an 'LS Destination' register"
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endm
+
+ // An "LI Destination" register
+
+ .macro ..li_destination, reg
+ .if (\reg != D0)
+ .if (\reg != D1)
+ .if (\reg != A0)
+ .if (\reg != A1)
+ .if (\reg != CTR)
+ .error "Expecting an 'LI Destination' register"
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endm
+
+ // An "LIA Destination" register
+
+ .macro ..lia_destination, reg
+ .if (\reg != D0)
+ .if (\reg != D1)
+ .if (\reg != A0)
+ .if (\reg != A1)
+ .if (\reg != TBAR)
+ .error "Expecting an 'LIA Destination' register"
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endm
+
+ // An "MR Source" register
+
+ .macro ..mr_source, reg
+ .if (\reg != D0)
+ .if (\reg != D1)
+ .if (\reg != A0)
+ .if (\reg != A1)
+ .if (\reg != P0)
+ .if (\reg != P1)
+ .if (\reg != CTR)
+ .if (\reg != PC)
+ .if (\reg != ETR)
+ .if (\reg != SPRG0)
+ .if (\reg != IFR)
+ .if (\reg != EMR)
+ .error "Expecting an 'MR Source' register"
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endm
+
+ // An "MR Destination" register
+
+ .macro ..mr_destination, reg
+ .if (\reg != D0)
+ .if (\reg != D1)
+ .if (\reg != A0)
+ .if (\reg != A1)
+ .if (\reg != P0)
+ .if (\reg != P1)
+ .if (\reg != CTR)
+ .if (\reg != PC)
+ .if (\reg != ETR)
+ .if (\reg != SPRG0)
+ .if (\reg != EMR)
+ .error "Expecting an 'MR Destination' register"
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endm
+
+
+ //////////////////////////////////////////////////////////////////////
+ // PORE address spaces
+ //////////////////////////////////////////////////////////////////////
+
+ // The ..set_address_space pseudo-op defines the default address
+ // space. It must be defined in order to use BRAA, BRAIA, BSR and
+ // CMPIBSR. Pseudo-ops are provided to set the default space of the
+ // program. Note that code assembled for PNOR will also work in the
+ // OCI space in the Sleep/Winkle engine.
+
+ .macro ..set_default_space, s
+ ..check_u16 (\s)
+ .set _PGAS_DEFAULT_SPACE, (\s)
+ .endm
+
+ .macro ..check_default_space
+ .if (_PGAS_DEFAULT_SPACE == PORE_SPACE_UNDEFINED)
+ .error "The PGAS default address space has not been defined"
+ .endif
+ .endm
+
+ ..set_default_space PORE_SPACE_UNDEFINED
+
+ .macro .oci
+ ..set_default_space PORE_SPACE_OCI
+ .endm
+
+ .macro .pnor
+ ..set_default_space PORE_SPACE_PNOR
+ .endm
+
+ .macro .seeprom
+ ..set_default_space PORE_SPACE_SEEPROM
+ .endm
+
+ .macro .otprom
+ ..set_default_space PORE_SPACE_OTPROM
+ .endm
+
+ .macro .pibmem
+ ..set_default_space PORE_SPACE_PIBMEM
+#ifndef PGAS_PPC
+ .pibmem_port (PORE_SPACE_PIBMEM & 0xf)
+#else
+ // NB: PGAS_PPC does not support relocatable PIBMEM addressing
+#endif
+ .endm
+
+
+ //////////////////////////////////////////////////////////////////////
+ // Address-Generation Pseudo Ops
+ //////////////////////////////////////////////////////////////////////
+
+ // .QUADA, .QUADIA
+
+ .macro .quada, offset:req
+ ..check_default_space
+ .long _PGAS_DEFAULT_SPACE
+ .long (\offset)
+ .endm
+
+ .macro .quadia, space:req, offset:req
+ ..check_u16 (\space)
+ .long (\space)
+ .long (\offset)
+ .endm
+
+ //////////////////////////////////////////////////////////////////////
+ // Bug workarounds
+ //////////////////////////////////////////////////////////////////////
+
+#ifndef IGNORE_HW274735
+
+ // HW274735 documents that BC and BS are broken for the PORE-GPE0/1
+ // pair. This bug is unfixed in POWER8, and by default we require BSI
+ // and BCI to be implemented as macros on all engines. For
+ // compatibility we continue to require that dx == D0.
+
+ .macro bsi, dx:req, offset:req, base:req, imm:req
+ ..d0 (\dx)
+ ld D0, (\offset), (\base)
+ ori D0, D0, (\imm)
+ std D0, (\offset), (\base)
+ .endm
+
+ .macro bci, dx:req, offset:req, base:req, imm:req
+ ..d0 (\dx)
+ ldandi D0, (\offset), (\base), ~(\imm)
+ std D0, (\offset), (\base)
+ .endm
+
+#endif // IGNORE_HW274735
+
+ //////////////////////////////////////////////////////////////////////
+ // "A"- and "IA"-form Instructions
+ //////////////////////////////////////////////////////////////////////
+
+ // BRAA (Branch Address) is a 'long branch' to an address in the
+ // default memory space.
+
+ .macro braa, offset:req
+ braia _PGAS_DEFAULT_SPACE, (\offset)
+ .endm
+
+ // LA (Load Address) loads the full address of an address in the
+ // default memory space.
+
+ .macro la, dest:req, offset:req
+ lia (\dest), _PGAS_DEFAULT_SPACE, (\offset)
+ .endm
+
+ // STA (Store Address) stores the full address of an address in the
+ // default memory space.
+
+ .macro sta, mem_offset:req, base:req, addr_offset:req
+ stia (\mem_offset), (\base), _PGAS_DEFAULT_SPACE, (\addr_offset)
+ .endm
+
+ // BSRIA is a subroutine branch into another memory space. This has to
+ // be emulated by a local subroutine branch and a BRAIA.
+
+ .macro bsria, space:req, offset:req
+ bsr 27742f
+ bra 27743f
+27742:
+ braia (\space), (\offset)
+27743:
+ .endm
+
+
+////////////////////////////////////////////////////////////////////////////
+// Extended Mnemonics, Macros and Special Cases
+////////////////////////////////////////////////////////////////////////////
+
+ //////////////////////////////////////////////////////////////////////
+ // TFB<c> - Test flags and branch conditionally
+ //////////////////////////////////////////////////////////////////////'
+
+ .macro ..tfb, dest, target, flags
+ ..data (\dest)
+ mr (\dest), IFR
+ andi (\dest), (\dest), (\flags)
+ branz (\dest), (\target)
+ .endm
+
+ .macro ..tfbn dest, target, flags
+ ..data (\dest)
+ mr (\dest), IFR
+ andi (\dest), (\dest), (\flags)
+ braz (\dest), (\target)
+ .endm
+
+ .macro tfbcs, dest:req, target:req
+ ..tfb (\dest), (\target), CC_C
+ .endm
+
+ .macro tfbcc, dest:req, target:req
+ ..tfbn (\dest), (\target), CC_C
+ .endm
+
+ .macro tfbvs, dest:req, target:req
+ ..tfb (\dest), (\target), CC_V
+ .endm
+
+ .macro tfbvc, dest:req, target:req
+ ..tfbn (\dest), (\target), CC_V
+ .endm
+
+ .macro tfbns, dest:req, target:req
+ ..tfb (\dest), (\target), CC_N
+ .endm
+
+ .macro tfbnc, dest:req, target:req
+ ..tfbn (\dest), (\target), CC_N
+ .endm
+
+ .macro tfbeq, dest:req, target:req
+ ..tfb (\dest), (\target), CC_Z
+ .endm
+
+ .macro tfbne, dest:req, target:req
+ ..tfbn (\dest), (\target), CC_Z
+ .endm
+
+ .macro tfbult, dest:req, target:req
+ ..tfb (\dest), (\target), CC_ULT
+ .endm
+
+ .macro tfbule, dest:req, target:req
+ ..tfbn (\dest), (\target), CC_UGT
+ .endm
+
+ .macro tfbuge, dest:req, target:req
+ ..tfbn (\dest), (\target), CC_ULT
+ .endm
+
+ .macro tfbugt, dest:req, target:req
+ ..tfb (\dest), (\target), CC_UGT
+ .endm
+
+ .macro tfbslt, dest:req, target:req
+ ..tfb (\dest), (\target), CC_SLT
+ .endm
+
+ .macro tfbsle, dest:req, target:req
+ ..tfbn (\dest), (\target), CC_SGT
+ .endm
+
+ .macro tfbsge, dest:req, target:req
+ ..tfbn (\dest), (\target), CC_SLT
+ .endm
+
+ .macro tfbsgt, dest:req, target:req
+ ..tfb (\dest), (\target), CC_SGT
+ .endm
+
+
+ //////////////////////////////////////////////////////////////////////
+ // TEB[N]<eng> - Test Engine and branch if [not] engine.
+ //////////////////////////////////////////////////////////////////////
+ //
+ // All but GPE0 use a 1-hot code.
+
+ .macro tebgpe0, dest:req, target:req
+ mr (\dest), IFR
+ andi (\dest), (\dest), 0xf
+ braz (\dest), (\target)
+ .endm
+
+ .macro tebgpe1, dest:req, target:req
+ mr (\dest), IFR
+ andi (\dest), (\dest), PORE_ID_GPE1
+ branz (\dest), (\target)
+ .endm
+
+ .macro tebslw, dest:req, target:req
+ mr (\dest), IFR
+ andi (\dest), (\dest), PORE_ID_SLW
+ branz (\dest), (\target)
+ .endm
+
+ .macro tebsbe, dest:req, target:req
+ mr (\dest), IFR
+ andi (\dest), (\dest), PORE_ID_SBE
+ branz (\dest), (\target)
+ .endm
+
+
+ .macro tebngpe0, dest:req, target:req
+ mr (\dest), IFR
+ andi (\dest), (\dest), 0xf
+ branz (\dest), (\target)
+ .endm
+
+ .macro tebngpe1, dest:req, target:req
+ mr (\dest), IFR
+ andi (\dest), (\dest), PORE_ID_GPE1
+ braz (\dest), (\target)
+ .endm
+
+ .macro tebnslw, dest:req, target:req
+ mr (\dest), IFR
+ andi (\dest), (\dest), PORE_ID_SLW
+ braz (\dest), (\target)
+ .endm
+
+ .macro tebnsbe, dest:req, target:req
+ mr (\dest), IFR
+ andi (\dest), (\dest), PORE_ID_SBE
+ braz (\dest), (\target)
+ .endm
+
+
+ //////////////////////////////////////////////////////////////////////
+ // EXTRPRC - Extract and right-justify the PIB/PCB return code
+ // TPRCB[N]Z - Test PIB return code and branch if [not] zero
+ // TPRCBGT - Test PIB return code and branch if greater-than
+ // TPRCBLE - Test PIB return code and branch if less-then or equal
+ //////////////////////////////////////////////////////////////////////
+ //
+ // To support cases where PORE code expects or must explicitly handle
+ // non-0 PIB return codes, the PIB return code and parity indication
+ // are stored in bits 32 (parity) and 33-35 (return code) of the IFR.
+ // These macros extract the four PIB/PCB status bits from the IFR and
+ // right-justifies them into the data register provided. For EXTRPRC
+ // that is the total function of the macro. The TPRCB[N]Z macros
+ // provide a simple non-destructive test and branch for zero (success)
+ // and non-zero (potential problem) codes after the extraction.
+ //
+ // In complex error handling scenarios one would typically compare the
+ // PIB return code against an upper-bound, e.g., the offline response
+ // (0x2), and then take further action. If the parity error bit is set
+ // then this would produce an aggregate "return code" higher than any
+ // that one would typically want to ignore. The TPRCBGT/TPRCBLE macros
+ // provide this function; however the test destroys the extracted
+ // return code so that if further analysis is required the code will
+ // need to be a extracted again.
+ //////////////////////////////////////////////////////////////////////
+
+ .macro extrprc, dest:req
+ ..data (\dest)
+ mr (\dest), IFR
+ extrdi (\dest), (\dest), 4, 32
+ .endm
+
+ .macro tprcbz, dest:req, target:req
+ extrprc (\dest)
+ braz (\dest), (\target)
+ .endm
+
+ .macro tprcbnz, dest:req, target:req
+ extrprc (\dest)
+ branz (\dest), (\target)
+ .endm
+
+ .macro tprcbgt, dest:req, target:req, bound:req
+ extrprc (\dest)
+ subs (\dest), (\dest), (\bound)
+ tfbugt (\dest), (\target)
+ .endm
+
+ .macro tprcble, dest:req, target:req, bound:req
+ extrprc (\dest)
+ subs (\dest), (\dest), (\bound)
+ tfbule (\dest), (\target)
+ .endm
+
+ //////////////////////////////////////////////////////////////////////
+ // LPCS - Load Pervasive Chiplet from Scom address
+ //////////////////////////////////////////////////////////////////////
+
+ .macro lpcs, dest:req, scom:req
+ ..pervasive_chiplet_id (\dest)
+ ..check_scom (\scom)
+ ls (\dest), (((\scom) >> 24) & 0x7f)
+ .endm
+
+
+ //////////////////////////////////////////////////////////////////////
+ // Shift/Mask extended mnemonics
+ //////////////////////////////////////////////////////////////////////
+
+ // All of the 'dot-dot' macros assume that error and identity
+ // checking has been done on the arguments already.
+
+ // The initial register-register rotate. If the incoming shift amount
+ // is 0 then the instruction generated is a simple MR.
+
+ .macro ..rotlrr, ra, rs, sh
+
+ .if (\sh) >= 32
+ rols (\ra), (\rs), 32
+ ..rotlr (\ra), ((\sh) - 32)
+ .elseif (\sh) >= 16
+ rols (\ra), (\rs), 16
+ ..rotlr (\ra), ((\sh) - 16)
+ .elseif (\sh) >= 8
+ rols (\ra), (\rs), 8
+ ..rotlr (\ra), ((\sh) - 8)
+ .elseif (\sh) >= 4
+ rols (\ra), (\rs), 4
+ ..rotlr (\ra), ((\sh) - 4)
+ .elseif (\sh) >= 1
+ rols (\ra), (\rs), 1
+ ..rotlr (\ra), ((\sh) - 1)
+ .else
+ mr (\ra), (\rs)
+ .endif
+
+ .endm
+
+
+ // Subsequent rotation of the same register. The SH should never be 0
+ // here.
+
+ .macro ..rotlr, ra, sh
+
+ .if (\sh) >= 32
+ rols (\ra), (\ra), 32
+ ..rotlr (\ra), ((\sh) - 32)
+ .elseif (\sh) >= 16
+ rols (\ra), (\ra), 16
+ ..rotlr (\ra), ((\sh) - 16)
+ .elseif (\sh) >= 8
+ rols (\ra), (\ra), 8
+ ..rotlr (\ra), ((\sh) - 8)
+ .elseif (\sh) >= 4
+ rols (\ra), (\ra), 4
+ ..rotlr (\ra), ((\sh) - 4)
+ .elseif (\sh) >= 1
+ rols (\ra), (\ra), 1
+ ..rotlr (\ra), ((\sh) - 1)
+
+ .endif
+
+ .endm
+
+
+ // RLDINM RA, RS, SH, MB, ME
+ //
+ // Defined as if there were an equivalent PowerPC instruction. The
+ // 'word' forms of the PowerPC instructions and extended mnemonics are
+ // undefined in order to catch programming typos.
+
+ .undefppc rlwinm, extrwi, rotlwi, rotrwi
+ .undefppc slwi, srwi
+
+ .macro rldinm, ra:req, rs:req, sh:req, mb:req, me:req
+
+ .if ((\sh) < 0) || ((\sh) > 63)
+ .error "SH must be in the range 0..63"
+ .endif
+ .if ((\mb) < 0) || ((\mb) > 63)
+ .error "MB must be in the range 0..63"
+ .endif
+ .if ((\me) < 0) || ((\me) > 63)
+ .error "ME must be in the range 0..63"
+ .endif
+
+ .if (((\mb) == 0) && ((\me) == 63) || ((\me) == ((\mb) - 1)))
+
+ // The mask is effectively 0..63, i.e., no mask. This is a
+ // simple rotate.
+
+ ..rotlrr (\ra), (\rs), (\sh)
+
+ .else
+
+ // We need a mask step. However if SH == 0 and RA == RS we can
+ // bypass the rotate step.
+
+ .if ((\sh) != 0) || ((\ra) != (\rs))
+ ..rotlrr (\ra), (\rs), (\sh)
+ .endif
+ .if ((\mb) <= (\me))
+
+ // This is a straightforward masking operation with a
+ // single mask.
+
+ andi (\ra), (\ra), ((0xffffffffffffffff >> (\mb)) & (0xffffffffffffffff << (63 - (\me))))
+ .else
+
+ // This is a wrapped mask.
+ // It is created as 2 masks OR-ed together - 0-ME and MB-63
+
+ andi (\ra), (\ra), (((0xffffffffffffffff >> 0) & (0xffffffffffffffff << (63 - (\me)))) | ((0xffffffffffffffff >> (\mb)) & (0xffffffffffffffff << (63 - 63))))
+ .endif
+
+ .endif
+
+ .endm
+
+ // RLDINM Extended Mnemonics
+ //
+ // Defined as if they were equivalent to PowerPC 32-bit extended
+ // mnemonics
+
+ .macro extldi, ra:req, rs:req, n:req, b:req
+ .if ((\n) < 0)
+ .error "EXTLDI requires N > 0"
+ .endif
+ rldinm (\ra), (\rs), (\b), 0, ((\n) - 1)
+ .endm
+
+ .macro extrdi, ra:req, rs:req, n:req, b:req
+ .if ((\n) < 0)
+ .error "EXTRDI requires N > 0"
+ .endif
+ rldinm (\ra), (\rs), (((\b) + (\n)) % 64), (64 - (\n)), 63
+ .endm
+
+ .macro rotldi, ra:req, rs:req, n:req
+ rldinm (\ra), (\rs), (\n), 0, 63
+ .endm
+
+
+ .macro rotrdi, ra:req, rs:req, n:req
+ rldinm (\ra), (\rs), (64 - (\n)), 0, 63
+ .endm
+
+
+ .macro sldi, ra:req, rs:req, n:req
+ rldinm (\ra), (\rs), (\n), 0, (63 - (\n))
+ .endm
+
+
+ .macro srdi, ra:req, rs:req, n:req
+ rldinm (\ra), (\rs), (64 - (\n)), (\n), 63
+ .endm
+
+
+ // RLDIMI RA, RS, SH, MB, ME
+ //
+ // Defined as if there were an equivalent PowerPC instruction. The
+ // 'word' forms of the PowerPC instructions and extended mnemonics are
+ // undefined in order to catch programming typos.
+ //
+ // Note that unlike the PowerPC instructions, here RLDIMI must destroy
+ // RS by masking and shifting it, and RA and RS may not be the same
+ // register.
+
+ .undefppc rlwimi, inslwi, insrwi
+
+ .macro rldimi, ra:req, rs:req, sh:req, mb:req, me:req
+
+ ..dxdy (\ra), (\rs)
+
+ // SH error checks are done by rldinm
+
+ .if (((\mb) == 0) && ((\me) == 63) || ((\me) == ((\mb) - 1)))
+
+ // The mask is effectively 0..63, i.e., no mask. This is a
+ // simple rotate of RS into RA
+
+ rotldi (\ra), (\rs), (\sh)
+
+ .else
+
+ // Rotate RS and AND with mask
+
+ rldinm (\rs), (\rs), (\sh), (\mb), (\me)
+
+ // Mask out the significant bits of RS, clear that section of
+ // RA, and logical OR RS into RA
+
+ .if ((\mb) <= (\me))
+
+ // This is a straightforward masking operation with a
+ // single mask.
+
+ andi (\ra), (\ra), \
+ (~((0xffffffffffffffff >> (\mb)) & (0xffffffffffffffff << (63 - (\me)))))
+ .else
+
+ // This is a wrapped mask.
+ // It is created as 2 masks OR-ed together - 0-ME and MB-63
+
+ andi (\ra), (\ra), \
+ (~(((0xffffffffffffffff >> 0) & (0xffffffffffffffff << (63 - (\me)))) | \
+ ((0xffffffffffffffff >> (\mb)) & (0xffffffffffffffff << (63 - 63)))))
+ .endif
+
+ or (\ra), D0, D1
+
+ .endif
+
+ .endm
+
+ // RLDIMI Extended Mnemonics
+ //
+ // Defined as if they were equivalent to PowerPC 32-bit extended
+ // mnemonics
+
+ .macro insldi, ra:req, rs:req, n:req, b:req
+ .if ((\n) < 0)
+ .error "INSLDI requires N > 0"
+ .endif
+ rldimi (\ra), (\rs), (64 - (\b)), (\b), ((\b) + (\n) - 1)
+ .endm
+
+ .macro insrdi, ra:req, rs:req, n:req, b:req
+ .if ((\n) < 0)
+ .error "INSRDI requires N > 0"
+ .endif
+ rldimi (\ra), (\rs), (64 - (\b) - (\n)), (\b), ((\b) + (\n) - 1)
+ .endm
+
+
+ //////////////////////////////////////////////////////////////////////
+ // .HOOK
+ //////////////////////////////////////////////////////////////////////
+
+ // The PoreVe (PORE Virtual Environment) is a PORE simulation
+ // environment that allows the programmer to embed C/C++ code into the
+ // PORE assembler source code, and arranges for the C/C++ code to be
+ // executed in-line with the PORE assembly code. Instances of the
+ // .hook macro are inserted into the assembler input by the
+ // hook_extractor script, to mark the locations where hooks are
+ // present. The hook reference is a string that combines the source
+ // file name with an index number to uniquely identify the hook.
+ //
+ // .hook <file name>_<sequence number>
+ //
+ // The .hook macro marks the location of each hook in the relocatable
+ // binaries with special symbols. The symbol name includes the hook
+ // reference, which is used to locate the hook in the HookManager
+ // symbol table. Because hooks can be defined in macros, a hook that
+ // appears once in a source file may appear multiple times in the
+ // final binary. For this reason each hook must also be tagged with a
+ // unique index number to avoid symbol name collisions. The
+ // complexity of the .hook macro is due to the necessity to decode a
+ // dynamic symbol value (_PGAS_HOOK_INDEX) into its binary string form
+ // to create the unique symbol name. The final hook symbol has the
+ // form:
+ //
+ // __hook__<unique>_<reference>
+ //
+ // where <unique> is a binary string. It is then straightforward to
+ // locate these symbols in the 'nm' output of the final link and
+ // create a map of final addresses to the hook routine to call (the
+ // <reference>) before executing the instruction at that address.
+ //
+ // Note: The maximum nesting depth of the recursive ..hook_helper
+ // macro is log2(index), and the assembler supports nesting of at
+ // least 32 which is much more than sufficient.
+
+ .set _PGAS_HOOK_INDEX, 0
+
+ .macro .hook, reference:req
+ .set _PGAS_HOOK_INDEX, (_PGAS_HOOK_INDEX + 1)
+ ..hook_helper _PGAS_HOOK_INDEX, "", \reference
+ .endm
+
+ .macro ..hook_helper, index, unique, reference
+ .ifeq \index
+ __hook__\unique\()_\reference\():
+ .elseif (\index % 2)
+ ..hook_helper (\index / 2), 1\unique, \reference
+ .else
+ ..hook_helper (\index / 2), 0\unique, \reference
+ .endif
+ .endm
+
+
+////////////////////////////////////////////////////////////////////////////
+// Help for Conversion from Old to New PGAS syntax
+////////////////////////////////////////////////////////////////////////////
+
+ .macro loadp, arg:vararg
+ .error "PGAS now implements 'lpcs' rather then 'loadp'"
+ .endm
+
+ .macro loadx, arg:vararg
+ .error "PGAS now implements 'la' rather than 'loadx'"
+ .endm
+
+#endif // __ASSEMBLER__
+
+#ifdef PGAS_PPC
+#include "pgas_ppc.h"
+#endif
+
+#endif // __PGAS_H__
diff --git a/roms/skiboot/libpore/pore_inline.h b/roms/skiboot/libpore/pore_inline.h
new file mode 100644
index 000000000..1af9199cf
--- /dev/null
+++ b/roms/skiboot/libpore/pore_inline.h
@@ -0,0 +1,883 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/hwpf/hwp/build_winkle_images/p8_slw_build/pore_inline.h $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2012,2014 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __PORE_INLINE_H__
+#define __PORE_INLINE_H__
+
+// $Id: pore_inline.h,v 1.20 2013/12/11 00:11:13 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/pore_inline.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** ***
+//-----------------------------------------------------------------------------
+
+// ** WARNING : This file is maintained as part of the OCC firmware. Do **
+// ** not edit this file in the PMX area or the hardware procedure area **
+// ** as any changes will be lost. **
+
+/// \file pore_inline.h
+/// \brief Inline assembler for PORE code
+///
+/// Note that this file defines several short macro symbols for register names
+/// and other mnemonics used by inline assembly. For this reason it would
+/// probably be best to only include this header when it was absolutely
+/// necessary, i.e., only in C files that explicitly use inline assembly and
+/// disassembly.
+
+#ifndef PPC_HYP
+#include <ctype.h>
+#include <stddef.h>
+#include <stdint.h>
+#endif // PPC_HYP
+#include "pgas.h"
+
+#if( defined(__cplusplus) && !defined(PLIC_MODULE) )
+extern "C" {
+#endif
+#if 0
+} /* So __cplusplus doesn't mess w/auto-indent */
+#endif
+
+
+#ifndef __ASSEMBLER__
+
+// PHYP tools do not support 'static' functions and variables as it interferes
+// with their concurrent patch methodology. So when compiling for PHYP the
+// PORE instruction "macros" are simply declared "inline". This also extends
+// into the implementation C files - so under PHYP all previosuly local static
+// functions will now be global functions. We retain 'static' to reduce code
+// size and improve abstraction for OCC applications.
+
+#ifdef PPC_HYP
+#define PORE_STATIC
+#include <p8_pore_api_custom.h>
+#else
+#define PORE_STATIC static
+#endif
+
+/// Error code strings from the PORE inline assembler/disassembler
+///
+/// The PoreInlineContext object stores error codes that occur during
+/// assembly as small integers. The '0' code indicates success. This is a
+/// table of strings that describe the codes. It will be instantiated in
+/// pore_inline.c
+
+extern const char *pore_inline_error_strings[];
+
+#ifdef __PORE_INLINE_ASSEMBLER_C__
+const char *pore_inline_error_strings[] = {
+ "No error",
+ "The inline assembler memory is full, or disassembly has reached the end of the memory area",
+ "The instruction requires an ImD24 operand",
+ "The LC is not aligned or the instruction requires an aligned operand",
+ "The branch target is unreachable (too distant)",
+ "A register operand is illegal for the given instruction",
+ "The instruction form requires a signed 16-bit immediate",
+ "Valid rotate lengths are 1, 4, 8, 16 and 32",
+ "The instruction requires a 20-bit signed immediate",
+ "The instruction requires a 24-bit unsigned immediate",
+ "A parameter to pore_inline_context_create() is invalid",
+ "The instruction form requires an unsigned 22-bit immediate",
+ "This error is due to a bug in the PORE inline assembler (Please report)",
+ "The 'source' label for pore_inline_branch_fixup() is illegal",
+ "The 'source' instruction for pore_inline_branch_fixup() is not a branch",
+ "The disassembler does not recognize the instruction as a PORE opcode",
+ "Instruction parity error during disassembly",
+ "The string form of the disassembly is too long to represent (Please report)`",
+ "Use HALT instead of WAIT 0 if the intention is to halt.",
+ "A putative SCOM address is illegal (has non-0 bits where 0s are expected)."
+};
+#endif /* __PORE_INLINE_ASSEMBLER_C__ */
+
+#endif /* __ASSEMBLER__ */
+
+#define PORE_INLINE_SUCCESS 0
+#define PORE_INLINE_NO_MEMORY 1
+#define PORE_INLINE_IMD24_ERROR 2
+#define PORE_INLINE_ALIGNMENT_ERROR 3
+#define PORE_INLINE_UNREACHABLE_TARGET 4
+#define PORE_INLINE_ILLEGAL_REGISTER 5
+#define PORE_INLINE_INT16_REQUIRED 6
+#define PORE_INLINE_ILLEGAL_ROTATE 7
+#define PORE_INLINE_INT20_REQUIRED 8
+#define PORE_INLINE_UINT24_REQUIRED 9
+#define PORE_INLINE_INVALID_PARAMETER 10
+#define PORE_INLINE_UINT22_REQUIRED 11
+#define PORE_INLINE_BUG 12
+#define PORE_INLINE_ILLEGAL_SOURCE_LC 13
+#define PORE_INLINE_NOT_A_BRANCH 14
+#define PORE_INLINE_UNKNOWN_OPCODE 15
+#define PORE_INLINE_PARITY_ERROR 16
+#define PORE_INLINE_DISASSEMBLY_OVERFLOW 17
+#define PORE_INLINE_USE_HALT 18
+#define PORE_INLINE_ILLEGAL_SCOM_ADDRESS 19
+
+
+/// Register name strings for the PORE inline assembler/disassembler
+
+extern const char *pore_inline_register_strings[16];
+
+// C++ requires that these arrays of strings be declared 'const' to avoid
+// warnings. But then you get warnings when the strings get stored into
+// non-const variables. The solution is to rename these arrays inside the
+// disassembler. If anyone has a better solution please let me know - Bishop
+
+#ifdef __PORE_INLINE_ASSEMBLER_C__
+const char* pore_inline_register_strings[16] = {
+ "P0", "P1", "A0", "A1", "CTR", "D0", "D1", "EMR",
+ "?", "ETR", "SPRG0", "?", "?", "?", "PC", "IFR"
+};
+#endif /* __PORE_INLINE_ASSEMBLER_C__ */
+
+
+// Shorthand forms of constants defined in pgas.h, defined for consistency
+// using the assembler-supported names. These constants are defined as an
+// enum to avoid name conflicts with some firmware symbols when the PORE
+// inline facility is used to create Host Boot procedures.
+
+enum {
+
+ // Shorthand register mnemonics, defined as an enum to avoid name clashes.
+
+ P0 = PORE_REGISTER_PRV_BASE_ADDR0,
+ P1 = PORE_REGISTER_PRV_BASE_ADDR1,
+ A0 = PORE_REGISTER_OCI_BASE_ADDR0,
+ A1 = PORE_REGISTER_OCI_BASE_ADDR1,
+ CTR = PORE_REGISTER_SCRATCH0,
+ D0 = PORE_REGISTER_SCRATCH1,
+ D1 = PORE_REGISTER_SCRATCH2,
+ EMR = PORE_REGISTER_ERROR_MASK,
+ ETR = PORE_REGISTER_EXE_TRIGGER,
+ SPRG0 = PORE_REGISTER_DATA0,
+ PC = PORE_REGISTER_PC,
+ IFR = PORE_REGISTER_IBUF_ID,
+
+ // PgP IBUF_ID values
+
+ PORE_GPE0 = PORE_ID_GPE0,
+ PORE_GPE1 = PORE_ID_GPE1,
+ PORE_SLW = PORE_ID_SLW,
+ PORE_SBE = PORE_ID_SBE,
+
+ // Condition Codes
+
+ CC_UGT = PORE_CC_UGT,
+ CC_ULT = PORE_CC_ULT,
+ CC_SGT = PORE_CC_SGT,
+ CC_SLT = PORE_CC_SLT,
+ CC_C = PORE_CC_C,
+ CC_V = PORE_CC_V,
+ CC_N = PORE_CC_N,
+ CC_Z = PORE_CC_Z,
+};
+
+// Pseudo-opcodes for LD/LDANDI/STD
+
+#define PORE_INLINE_PSEUDO_LD 0
+#define PORE_INLINE_PSEUDO_LDANDI 1
+#define PORE_INLINE_PSEUDO_STD 2
+
+
+// Private version of _BIG_ENDIAN
+
+#ifndef _BIG_ENDIAN
+#define PORE_BIG_ENDIAN 0
+#else
+#define PORE_BIG_ENDIAN _BIG_ENDIAN
+#endif
+
+
+/// Maximum size of disassembly strings
+///
+/// This is currently sufficient for PORE_INLINE_LISTING_MODE. We don't want
+/// to make this too long since the PoreInlineDisassembly object may be on the
+/// stack in embedded applications.
+#define PORE_INLINE_DISASSEMBLER_STRING_SIZE 128
+
+
+/// Generate PORE instruction parity
+///
+/// This flag is an option to pore_inline_context_create(). If set, PORE
+/// inline assembly sets the instruction parity bit for each assembled
+/// instruction; otherwise the instruction parity bit is always 0.
+#define PORE_INLINE_GENERATE_PARITY 0x01
+
+/// Check PORE instruction parity
+///
+/// This flag is an option to pore_inline_context_create(). If set, PORE
+/// inline disassembly checks the instruction parity bit for each disassembled
+/// instruction, failing with PORE_INLINE_PARITY_ERROR if the parify is not
+/// correct. Otherwise the instruction parity bit is ignored during
+/// disassembly.
+#define PORE_INLINE_CHECK_PARITY 0x02
+
+/// Disassemble in listing mode
+///
+/// This flag is an option to pore_inline_context_create(). If set, then
+/// generate disassembly strings in the form of a listing that contains
+/// location counters and encoded instructions as well as their diassembly.
+/// By default the disassembly strings do not contain this information and can
+/// be fed back in as source code to a PORE assembler.
+#define PORE_INLINE_LISTING_MODE 0x04
+
+/// Disassemble in data mode
+///
+/// This flag is an option to pore_inline_context_create(). If set, then
+/// generate disassembly assuming that the context contains data rather than
+/// text. Normally data is disassembled as .long directives, however if the
+/// context is unaligned or of an odd length then .byte directives may be used
+/// as well. This option can be used in conjunction with
+/// PORE_INLINE_LISTING_MODE and PORE_INLINE_8_BYTE_DATA.
+///
+/// Note: An intelligent application can switch between the default text
+/// disassembly and data disassembly by manipulating the \a options field of
+/// the PoreInlineContext between calls of pore_inline_disassemble().
+#define PORE_INLINE_DISASSEMBLE_DATA 0x08
+
+/// Disassemble data in 8-byte format
+///
+/// This flag is an option to pore_inline_context_create(). If set, then if
+/// PORE_INLINE_DISASSEMBLE_DATA is also set then generate data disassembly as
+/// 8-byte values rather then the default 4-byte values. Normally data is
+/// disassembled as .quad directives under this option, however if the context
+/// is unaligned or of an odd length then .long and .byte directives may be
+/// used as well. This option can be used in conjunction with
+/// PORE_INLINE_LISTING_MODE.
+///
+/// Note: An intelligent application can switch between the default text
+/// disassembly and data disassembly by manipulating the \a options field of
+/// the PoreInlineContext between calls of pore_inline_disassemble().
+#define PORE_INLINE_8_BYTE_DATA 0x10
+
+/// Disassemble unrecognized opcodes as 4-byte data
+///
+/// This flag is an option to pore_inline_context_create(). If set, then
+/// any putative instruction with an unrecognized opcode will be silently
+/// diassembled as 4-byte data.
+///
+/// This option was added to allow error-free disassembly of
+/// non-parity-protected PORE text sections that contain 0x00000000 alignment
+/// padding, and is not guaranteed to produce correct or consistent results in
+/// any other case.
+#define PORE_INLINE_DISASSEMBLE_UNKNOWN 0x20
+
+
+#ifndef __ASSEMBLER__
+
+/// The type of location counters for the PORE inline assembler
+
+typedef uint32_t PoreInlineLocation;
+
+/// PORE inline assembler context
+///
+/// See the documentation page \ref pore_inline_assembler and the function
+/// pore_inline_context_create() for futher details.
+
+typedef struct {
+
+ /// The memory area to receive the inline assembly
+ ///
+ /// This field is never modified, allowing the *reset* APIs to function.
+ ///
+ /// Note: C++ does not allow arithmetic on void* objects, so we use the
+ /// Linux convention of storing memory addresses as type 'unsigned long'.
+ unsigned long memory;
+
+ /// The original size of the memory area to receive the inline assembly
+ ///
+ /// This field is never modified, allowing the *reset* APIs to function.
+ size_t size;
+
+ /// The original Location Counter (associated with \a memory)
+ ///
+ /// This field is never modified, allowing the *reset* APIs to function.
+ PoreInlineLocation original_lc;
+
+ /// The memory address associated with the current LC
+ ///
+ /// Note: C++ does not allow arithmetic on void* objects, so we use the
+ /// Linux convention of storing memory addresses as type 'unsigned long'.
+ unsigned long lc_address;
+
+ /// The remaining size of the memory area to receive the inline assembly
+ size_t remaining;
+
+ /// The bytewise Location Counter of the assembled code
+ PoreInlineLocation lc;
+
+ /// Inline assembly options
+ ///
+ /// This field is never modified, allowing the *reset* APIs to function.
+ int options;
+
+ /// The last error code generated by the inline assembler
+ int error;
+
+} PoreInlineContext;
+
+
+/// PORE inline disassembler result
+///
+/// This object holds the disassembly produced by pore_inline_disassemble().
+/// See documentation for that function for complete details.
+
+typedef struct {
+
+ /// The context as it existed when the instruction was assembled
+ ///
+ /// Disassembling an instruction modifies the context provided to
+ /// pore_inline_disassemble() to point to the next instruction. This
+ /// structure stores a copy of the context at the initial call of
+ /// pore_inline_disassemble(), that is, the context in effect when the
+ /// dissassembled instruction was assembled.
+ PoreInlineContext ctx;
+
+ /// The first 32 bits of every instruction
+ uint32_t instruction;
+
+ /// The opcode; bits 0..6 of the instruction
+ int opcode;
+
+ /// A flag - If set the opcode is for a 12-byte instruction
+ int long_instruction;
+
+ /// The parity bit; bit 7 of the instruction
+ int parity;
+
+ /// The register specifier at bits 8..11 of the instruction
+ ///
+ /// This register is sometimes called the source, sometimes the target,
+ /// depending on the opcode.
+ int r0;
+
+ /// The register specifier at bits 12..15 of the instruction
+ ///
+ /// This register is always called the 'source' but is named generically
+ /// here since sometimes the specifier at bits 8..11 is also called a
+ /// 'source'.
+ int r1;
+
+ /// 'ImD16' is the signed 16-bit immediate for short immediate adds and
+ /// subtracts. For the rotate instruction this field also contains the
+ /// rotate count which is either 1, 4, 8, 16 or 32.
+ int16_t imd16;
+
+ /// 'ImD20' is the 20-bit signed immediate for the LOAD20 instruction
+ int32_t imd20;
+
+ /// 'ImD24' is the 24-bit unsigned immediate for the WAIT instruction
+ uint32_t imd24;
+
+ /// 'ImD64' is the 64-bit immediate for data immediates and BRAI. This
+ /// field is only set for 3-word instructions.
+ uint64_t imd64;
+
+ /// 'ImPCO20' is a signed, 20-bit word offset for branch instructions
+ int32_t impco20;
+
+ /// 'ImPCO24' is a signed, 24-bit word offset for branch instructions
+ int32_t impco24;
+
+ /// For imA24 opcodes, this indicates memory/pib (1/0) addressing..
+ int memory_space;
+
+ /// This is the base register specifier - either a memory (OCI) base
+ /// register or a pervasive base register - for Read/Write operations.
+ /// Note that this is a PORE register index, not simply 0/1.
+ int base_register;
+
+ /// This is the 22-bit signed offset for memory (OCI) addressing. This
+ /// unsigned offset is added to a memory base register (A0/A1) to form the
+ /// final 32-bit address.
+ uint32_t memory_offset;
+
+ /// This field contains the port number and local address portions of the
+ /// PIB/PCB address for load/store operations that target the PIB/PCB.
+ /// Note that bits 0..11 will always be 0 in this address. Bits 1..7 (the
+ /// multicast bit and chiplet id) are sourced from the associated
+ /// pervasive base register when the instruction executes.
+ uint32_t pib_offset;
+
+ /// The update bit of the SCAND instruction
+ int update;
+
+ /// The capture bit of the SCAND instruction
+ int capture;
+
+ /// The scan length from a SCAND instruction
+ int scan_length;
+
+ /// The scan select from a SCAND instruction
+ uint32_t scan_select;
+
+ /// The address offset from a SCAND instruction
+ uint32_t scan_offset;
+
+ /// The string form of the disassembly.
+ ///
+ /// The disassembly string is \e not terminated by a newline. In listing
+ /// mode the disassembly string \e will contain embedded newlines for long
+ /// instructions.
+ char s[PORE_INLINE_DISASSEMBLER_STRING_SIZE];
+
+ /// The data (for data disassembly)
+ ///
+ /// This is either 1, 4 or 8 bytes in host byte order.
+ uint64_t data;
+
+ /// The size of the disassembled \a data field (for data disassembly)
+ size_t data_size;
+
+ /// Was this location disassembled as an instruction (0) or as data (1)
+ int is_data;
+
+} PoreInlineDisassembly;
+
+
+// These are internal APIs - they are not needed by application code.
+
+void
+pore_inline_be32(unsigned long p, uint32_t x);
+
+void
+pore_inline_be64(unsigned long p, uint64_t x);
+
+uint32_t
+pore_inline_host32(unsigned long p);
+
+uint64_t
+pore_inline_host64(unsigned long p);
+
+int
+pore_inline_parity(uint32_t instruction, uint64_t imd64);
+
+void
+pore_inline_context_bump(PoreInlineContext *ctx, size_t bytes);
+
+int
+pore_inline_instruction1(PoreInlineContext *ctx, int opcode, uint32_t operand);
+
+int
+pore_inline_instruction3(PoreInlineContext *ctx, int opcode, uint32_t operand,
+ uint64_t imm);
+
+int
+pore_inline_bra(PoreInlineContext *ctx,
+ int opcode, PoreInlineLocation target);
+
+int
+pore_inline_brac(PoreInlineContext *ctx,
+ int opcode, int reg, PoreInlineLocation target);
+
+int
+pore_inline_cmpibra(PoreInlineContext *ctx,
+ int opcode, int reg,
+ PoreInlineLocation target, uint64_t imm);
+
+int
+pore_inline_brad(PoreInlineContext *ctx, int opcode, int reg);
+
+int
+pore_inline_ilogic(PoreInlineContext *ctx,
+ int opcode, int dest, int src, uint64_t imm);
+int
+pore_inline_alurr(PoreInlineContext *ctx,
+ int opcode, int dest, int src1, int src2);
+
+int
+pore_inline_adds(PoreInlineContext *ctx,
+ int opcode, int dest, int src, int imm);
+
+int
+pore_inline_load_store(PoreInlineContext *ctx,
+ int opcode, int src_dest, int32_t offset, int base,
+ uint64_t imm);
+
+
+// These are utility APIs that may be required by special-purpose code that
+// uses the pore_inline library.
+
+void
+pore_inline_decode_instruction(PoreInlineDisassembly* dis,
+ uint32_t instruction);
+
+void
+pore_inline_decode_imd64(PoreInlineDisassembly* dis, uint64_t imd64);
+
+
+// These are the inline PORE instructions, extended mnemonics and pseudo-ops
+// to be used by application code.
+
+/// Set a location counter variable from a context
+///
+/// This is a macro that sets the \a var (of type PoreInlineLocation) to the
+/// current location counter of the \a ctx. The macro produces an expression
+/// that evaluates to 0 so that it can be used in the logical-OR expressions
+/// used to define inline assembly sequences.
+
+#define PORE_LOCATION(ctx, var) (((var) = (ctx)->lc), 0)
+
+int
+pore_inline_context_create(PoreInlineContext *context,
+ void *memory,
+ size_t size,
+ PoreInlineLocation lc,
+ int options);
+
+void
+pore_inline_context_reset(PoreInlineContext *context);
+
+void
+pore_inline_context_reset_excursion(PoreInlineContext *context);
+
+void
+pore_inline_context_copy(PoreInlineContext *dest, PoreInlineContext *src);
+
+
+int
+pore_inline_branch_fixup(PoreInlineContext *ctx,
+ PoreInlineLocation source,
+ PoreInlineLocation target);
+
+
+int
+pore_inline_disassemble(PoreInlineContext *ctx, PoreInlineDisassembly *dis);
+
+
+// Native PORE instruction assembly, using PGAS opcode names and operand
+// ordering rules.
+
+// NOP, TRAP, RET
+
+PORE_STATIC inline int
+pore_NOP(PoreInlineContext *ctx)
+{
+ return pore_inline_instruction1(ctx, PGAS_OPCODE_NOP, 0);
+}
+
+
+PORE_STATIC inline int
+pore_TRAP(PoreInlineContext *ctx)
+{
+ return pore_inline_instruction1(ctx, PGAS_OPCODE_TRAP, 0);
+}
+
+
+PORE_STATIC inline int
+pore_RET(PoreInlineContext *ctx)
+{
+ return pore_inline_instruction1(ctx, PGAS_OPCODE_RET, 0);
+}
+
+
+// WAITS, HALT, HOOKI
+
+int
+pore_WAITS(PoreInlineContext *ctx, uint32_t cycles);
+
+PORE_STATIC inline int
+pore_HALT(PoreInlineContext *ctx)
+{
+ return pore_inline_instruction1(ctx, PGAS_OPCODE_WAITS, 0);
+}
+
+int
+pore_HOOKI(PoreInlineContext *ctx, uint32_t index, uint64_t imm);
+
+
+// BRA, BSR, LOOP
+
+PORE_STATIC inline int
+pore_BRA(PoreInlineContext *ctx, PoreInlineLocation target)
+{
+ return pore_inline_bra(ctx, PGAS_OPCODE_BRA, target);
+}
+
+PORE_STATIC inline int
+pore_BSR(PoreInlineContext *ctx, PoreInlineLocation target)
+{
+ return pore_inline_bra(ctx, PGAS_OPCODE_BSR, target);
+}
+
+PORE_STATIC inline int
+pore_LOOP(PoreInlineContext *ctx, PoreInlineLocation target)
+{
+ return pore_inline_bra(ctx, PGAS_OPCODE_LOOP, target);
+}
+
+
+// BRAZ, BRANZ
+
+PORE_STATIC inline int
+pore_BRAZ(PoreInlineContext *ctx, int reg, PoreInlineLocation target)
+{
+ return pore_inline_brac(ctx, PGAS_OPCODE_BRAZ, reg, target);
+}
+
+
+PORE_STATIC inline int
+pore_BRANZ(PoreInlineContext *ctx, int reg, PoreInlineLocation target)
+{
+ return pore_inline_brac(ctx, PGAS_OPCODE_BRANZ, reg, target);
+}
+
+
+// CMPIBRAEQ, CMPIBRANE, CMPIBSREQ
+
+PORE_STATIC inline int
+pore_CMPIBRAEQ(PoreInlineContext *ctx,
+ int reg, PoreInlineLocation target, uint64_t imm)
+{
+ return pore_inline_cmpibra(ctx, PGAS_OPCODE_CMPIBRAEQ, reg, target, imm);
+}
+
+
+PORE_STATIC inline int
+pore_CMPIBRANE(PoreInlineContext *ctx,
+ int reg, PoreInlineLocation target, uint64_t imm)
+{
+ return pore_inline_cmpibra(ctx, PGAS_OPCODE_CMPIBRANE, reg, target, imm);
+}
+
+
+PORE_STATIC inline int
+pore_CMPIBSREQ(PoreInlineContext *ctx,
+ int reg, PoreInlineLocation target, uint64_t imm)
+{
+ return pore_inline_cmpibra(ctx, PGAS_OPCODE_CMPIBSREQ, reg, target, imm);
+}
+
+
+// BRAD, BSRD
+
+PORE_STATIC inline int
+pore_BRAD(PoreInlineContext *ctx, int reg) {
+ return pore_inline_brad(ctx, PGAS_OPCODE_BRAD, reg);
+}
+
+PORE_STATIC inline int
+pore_BSRD(PoreInlineContext *ctx, int reg) {
+ return pore_inline_brad(ctx, PGAS_OPCODE_BSRD, reg);
+}
+
+
+// ANDI, ORI, XORI
+
+PORE_STATIC inline int
+pore_ANDI(PoreInlineContext *ctx, int dest, int src, uint64_t imm)
+{
+ return pore_inline_ilogic(ctx, PGAS_OPCODE_ANDI, dest, src, imm);
+}
+
+PORE_STATIC inline int
+pore_ORI(PoreInlineContext *ctx, int dest, int src, uint64_t imm)
+{
+ return pore_inline_ilogic(ctx, PGAS_OPCODE_ORI, dest, src, imm);
+}
+
+PORE_STATIC inline int
+pore_XORI(PoreInlineContext *ctx, int dest, int src, uint64_t imm)
+{
+ return pore_inline_ilogic(ctx, PGAS_OPCODE_XORI, dest, src, imm);
+}
+
+
+// AND, OR, XOR, ADD, SUB
+
+PORE_STATIC inline int
+pore_AND(PoreInlineContext *ctx, int dest, int src1, int src2)
+{
+ return pore_inline_alurr(ctx, PGAS_OPCODE_AND, dest, src1, src2);
+}
+
+PORE_STATIC inline int
+pore_OR(PoreInlineContext *ctx, int dest, int src1, int src2)
+{
+ return pore_inline_alurr(ctx, PGAS_OPCODE_OR, dest, src1, src2);
+}
+
+PORE_STATIC inline int
+pore_XOR(PoreInlineContext *ctx, int dest, int src1, int src2)
+{
+ return pore_inline_alurr(ctx, PGAS_OPCODE_XOR, dest, src1, src2);
+}
+
+PORE_STATIC inline int
+pore_ADD(PoreInlineContext *ctx, int dest, int src1, int src2)
+{
+ return pore_inline_alurr(ctx, PGAS_OPCODE_ADD, dest, src1, src2);
+}
+
+PORE_STATIC inline int
+pore_SUB(PoreInlineContext *ctx, int dest, int src1, int src2)
+{
+ return pore_inline_alurr(ctx, PGAS_OPCODE_SUB, dest, src1, src2);
+}
+
+
+// ADDS, SUBS
+
+PORE_STATIC inline int
+pore_ADDS(PoreInlineContext *ctx, int dest, int src, int imm)
+{
+ return pore_inline_adds(ctx, PGAS_OPCODE_ADDS, dest, src, imm);
+}
+
+PORE_STATIC inline int
+pore_SUBS(PoreInlineContext *ctx, int dest, int src, int imm)
+{
+ return pore_inline_adds(ctx, PGAS_OPCODE_SUBS, dest, src, imm);
+}
+
+
+// NEG, MR, ROLS, LS, LI
+
+int
+pore_NEG(PoreInlineContext *ctx, int dest, int src);
+
+int
+pore_MR(PoreInlineContext *ctx, int dest, int src);
+
+int
+pore_ROLS(PoreInlineContext *ctx, int dest, int src, int imm);
+
+int
+pore_LS(PoreInlineContext *ctx, int dest, int imm);
+
+int
+pore_LI(PoreInlineContext *ctx, int dest, uint64_t imm);
+
+
+// LD, LDANDI, STD, STI, BSI, BCI
+
+PORE_STATIC inline int
+pore_LD(PoreInlineContext *ctx, int dest, int32_t offset, int base)
+{
+ return
+ pore_inline_load_store(ctx,
+ PORE_INLINE_PSEUDO_LD, dest, offset, base, 0);
+}
+
+PORE_STATIC inline int
+pore_LDANDI(PoreInlineContext *ctx,
+ int dest, int32_t offset, int base, uint64_t imm)
+{
+ return
+ pore_inline_load_store(ctx,
+ PORE_INLINE_PSEUDO_LDANDI,
+ dest, offset, base, imm);
+}
+
+PORE_STATIC inline int
+pore_STD(PoreInlineContext *ctx, int src, int32_t offset, int base)
+{
+ return
+ pore_inline_load_store(ctx,
+ PORE_INLINE_PSEUDO_STD, src, offset, base, 0);
+}
+
+PORE_STATIC inline int
+pore_STI(PoreInlineContext *ctx, int32_t offset, int base, uint64_t imm)
+{
+ return
+ pore_inline_load_store(ctx,
+ PGAS_OPCODE_STI, 0, offset, base, imm);
+}
+
+
+#ifdef IGNORE_HW274735
+
+// BSI and BCI are redacted as instructions and reimplemented as "macros" due
+// to HW274735, unless specifically overridden. Note that the inline assembler
+// will allow D1 to be used as scratch here, unlike the underlying hardware
+// instruction.
+
+PORE_STATIC inline int
+pore_BSI(PoreInlineContext *ctx,
+ int src, int32_t offset, int base, uint64_t imm)
+{
+ return
+ pore_inline_load_store(ctx,
+ PGAS_OPCODE_BSI, src, offset, base, imm);
+}
+
+PORE_STATIC inline int
+pore_BCI(PoreInlineContext *ctx,
+ int src, int32_t offset, int base, uint64_t imm)
+{
+ return
+ pore_inline_load_store(ctx,
+ PGAS_OPCODE_BCI, src, offset, base, imm);
+}
+
+#else
+
+PORE_STATIC inline int
+pore_BSI(PoreInlineContext *ctx,
+ int src, int32_t offset, int base, uint64_t imm)
+{
+ return
+ ((pore_LD(ctx, src, offset, base) ||
+ pore_ORI(ctx, src, src, imm) ||
+ pore_STD(ctx, src, offset, base)) ? ctx->error : 0);
+}
+
+PORE_STATIC inline int
+pore_BCI(PoreInlineContext *ctx,
+ int src, int32_t offset, int base, uint64_t imm)
+{
+ return
+ ((pore_LDANDI(ctx, src, offset, base, ~imm) ||
+ pore_STD(ctx, src, offset, base)) ? ctx->error : 0);
+}
+
+#endif // IGNORE_HW274735
+
+
+// BRAIA
+
+int
+pore_BRAIA(PoreInlineContext *ctx,
+ uint16_t address_space, uint32_t offset);
+
+
+// SCAND
+
+int
+pore_SCAND(PoreInlineContext *ctx,
+ int update, int capture, uint16_t length,
+ uint32_t select, uint32_t offset);
+
+#endif /* __ASSEMBLER__ */
+
+#if 0
+{ /* So __cplusplus doesn't mess w/auto-indent */
+#endif
+#if( defined(__cplusplus) && !defined(PLIC_MODULE) )
+}
+#endif
+
+#endif /* __PORE_INLINE_H__ */
+
diff --git a/roms/skiboot/libpore/pore_inline_assembler.c b/roms/skiboot/libpore/pore_inline_assembler.c
new file mode 100644
index 000000000..5747c6f4d
--- /dev/null
+++ b/roms/skiboot/libpore/pore_inline_assembler.c
@@ -0,0 +1,1509 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/hwpf/hwp/build_winkle_images/p8_slw_build/pore_inline_assembler.c $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2012,2014 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: pore_inline_assembler.c,v 1.22 2013/12/11 00:11:14 bcbrock Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/pore_inline_assembler.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2013
+// *! All Rights Reserved -- Property of IBM
+// *! *** ***
+//-----------------------------------------------------------------------------
+
+// ** WARNING : This file is maintained as part of the OCC firmware. Do **
+// ** not edit this file in the PMX area or the hardware procedure area **
+// ** as any changes will be lost. **
+
+/// \file pore_inline_assembler.c
+/// \brief Inline PGAS assembler for PgP/Stage1 PORE
+///
+/// \page pore_inline_assembler PORE Inline Assembler and Disassembler
+///
+/// Several procedures targeting the PORE engine require inline assembly and
+/// disassembly of PORE code, that is, they require that PORE instructions be
+/// assembled/disassembled directly into/from a host memory buffer. This page
+/// describes these facilities. The APIs described here are implemented in
+/// the files pore_inline.h, pore_inline_assembler.c and
+/// pore_inline_disassembler.c. Both the inline assembelr and disassembler
+/// conform to the PGAS assembly format for PORE.
+///
+/// Both inline assembly and disassembly make use of a PoreInlineContext
+/// structure. This structure represents the state of a memory area being
+/// targeted for inline assembly and disassembly. The context is initialized
+/// with the pore_inline_context_create() API, and a pointer to an instance of
+/// this structure appears as the first argument of all assembler/disassembler
+/// APIs. As assembly/disassembly progresses the PoreInlineContext keeps
+/// track of how much host memory area has been filled by assembled code or
+/// scanned by the disassebler.
+///
+/// Assembler/disassembler APIs are predicates that return 0 for success and a
+/// non-zero error code for failure. In the event of failure, the error code
+/// (a small integer) is also stored in the \a error field of the context
+/// structure. String forms of the error codes are also available in the
+/// global array pore_inline_error_strings[].
+///
+/// The assembler always produces PORE code in the PORE-native big-endian
+/// format. Likewise, the diassembler assumes the host memory to be
+/// disassembled contains PORE code in big-endian format.
+///
+/// \section Initialization
+///
+/// Before invoking inline assembly/disassembly APIs, an instance of a
+/// PoreInlineContext structure must be initialized using the
+/// pore_inline_context_create() API. For assembly, the context describes the
+/// host memory buffer that will contain the assembled code. For disassembly,
+/// the context describes the host memory area that contains the code to be
+/// disassembled. Full documentation is available for
+/// pore_inline_context_create(), including documentation for options that
+/// control assembly and disassembly. The implementation also provides a
+/// 'copy operator' for the context, pore_inline_context_copy().
+///
+/// An example of initializing a context for inline assembly with parity
+/// checking appears below.
+///
+/// \code
+///
+/// PoreInlineContext ctx;
+/// uint32_t buf[BUFSIZE];
+///
+/// rc = pore_inline_context_create(&ctx, buf, BUFSIZE * 4, 0,
+/// PORE_INLINE_CHECK_PARITY);
+/// if (rc) . . . Handle Error
+///
+/// \endcode
+///
+/// Applications that reuse the same memory buffer for assembling and
+/// processing multiple PORE programs can 'reset' the context between uses by
+/// using the pore_inline_context_reset() API. pore_inline_context_reset()
+/// resets the location counter and memory extent to their initial (creation)
+/// values, and the context error code is cleared. Any options specified at
+/// creation remain as they were.
+///
+/// \section Assembler
+///
+/// The inline assembler implements each PORE/PGAS instruction as individual
+/// function calls. The APIs are consistently named \c pore_\<OPCODE\>, where
+/// \c \<OPCODE\> is a PGAS mnemonic in upper case. The arguments to each
+/// opcode appear in the same order that they appear in the source-level
+/// assembler, with appropriate C-language types. The supported opcode APIs
+/// are defined in pore_inline.h
+///
+/// Since the PORE instruction APIs are effectivly predicates, linear code
+/// sequences are easily assembled using the C-language logical OR construct.
+/// Any non-0 return code will immediately break the sequence and set the
+/// expression value to 1. The failure code can then be recovered from the \a
+/// error field of the context. This coding technique is illustrated in the
+/// following example of assembling a memory-memory copy sequence.
+///
+/// \code
+///
+/// PoreInlineContext ctx;
+/// int error;
+///
+/// . . . // Initialize context
+///
+/// error =
+/// pore_LD(&ctx, D0, 0, A0) ||
+/// pore_STD(&ctx, D0, 0, A1);
+///
+/// if (error) <. . . Handle error based on ctx.error>
+///
+/// \endcode
+///
+/// The above example generates code equivalent to
+///
+/// \code
+///
+/// ld D0, 0, A0
+/// std D0, 0, A1
+///
+/// \endcode
+///
+/// Again, if an error were to occur during assembly, inline assembly would
+/// stop (and the logical OR would terminate) at the point of failure. In
+/// particular, the inline assembler will never allow assembled code to exceed
+/// the bounds of the memory area defined by the initial call of
+/// pore_inline_context_create() that defines the assembler memory space.
+///
+///
+/// \subsection Register Names and Other Mnemonics
+///
+/// The header file pore_inline.h defines macros for the register mnemonics.
+///
+/// - D0, D1 : 64-bit data registers
+/// - A0, A1 : 32-bit address registers
+/// - P0, P1 : 7-bit Pervasive chiplet id registers
+/// - CTR : 24-bit ounter register
+/// - PC : 48-bit Program Counter
+/// - ETR : 64-bit EXE-Trigger Register (Low-order 32 bits are writable)
+/// - EMR : The Error Mask Register
+/// - IFR : ID/Flags Register
+/// - SPRG0 : 32-bit Special-Purpose General Register 0
+///
+/// Mnemonics for the condition code bits are also defined by pore_inline.h
+/// using the PGAS mnemonics.
+///
+///
+/// \subsection Assembling Branches
+///
+/// Opcodes that implement relative branches require that the branch target be
+/// specified as a <em> location counter </em>. Once initialized, the current
+/// location counter is available as the \a lc field of the PoreInlineContext
+/// object controlling the assembly. The \a lc field is the only field
+/// (besides the error code held in the \a error field) that application code
+/// should ever reference. The inline assembler also provides a typedef
+/// PoreInlineLocation to use for location counters, as well as the macro
+/// PORE_LOCATION() to define a location variable inline with the code flow.
+///
+/// \subsubsection Backward Branches
+///
+/// Backward branches are straightforward. For example, the memory-memory
+/// copy example from earlier can be converted into a loop as shown below. The
+/// \a loop_target variable is initialized with the location counter of the
+/// first instruction of the loop. The final instruction of the loop then
+/// branches back to the \a loop_target.
+///
+/// \code
+///
+/// PoreInlineContext ctx;
+/// PoreInlineLocation loop_target = 0; // See ** below the example
+/// int error;
+///
+/// . . . // Initialize context
+///
+/// error =
+/// PORE_LOCATION(&ctx, loop_target) ||
+/// pore_LD(&ctx, D0, 0, A0) ||
+/// pore_STD(&ctx, D0, 0, A1) ||
+/// pore_ADDS(&ctx, A0, A0, 8) ||
+/// pore_ADDS(&ctx, A1, A1, 8) ||
+/// pore_LOOP(&ctx, loop_target);
+///
+/// if (error) <. . . Handle error based on ctx.error>
+///
+/// \endcode
+///
+/// The above inline assembler sequence is equivalent to the PGAS code
+/// sequence:
+///
+/// \code
+///
+/// loop_target:
+/// ld D0, 0, A0
+/// std D0, 0, A1
+/// adds A0, A0, 8
+/// adds A1, A1, 8
+/// loop loop_target
+///
+/// \endcode
+///
+/// ** Location counters used as loop targets may need to be initialized,
+/// otherwise the compiler may issue a warning that the variable "may be used
+/// uninitialized", although in well-written code this would never happen.
+///
+///
+/// \subsubsection Forward Branches
+///
+/// Forward branches are more complex. Since the target location counter is
+/// not known until the target has been assembled, the inline assembler
+/// provides the API pore_inline_branch_fixup() to fix up forward branches
+/// once the actual target is known. This is illustrated in the simple code
+/// sequence below, where an instruction is conditionally skipped.
+///
+/// \code
+///
+/// PoreInlineContext ctx;
+/// PoreInlineLocation source = 0, target = 0;
+/// int error, rc;
+///
+/// . . . // Initialize context
+///
+/// error =
+/// PORE_LOCATION(&ctx, source) ||
+/// pore_BRANZ(&ctx, D0, source) ||
+/// pore_ADDS(&ctx, D1, D1, 1) ||
+/// PORE_LOCATION(&ctx, target) ||
+/// pore_LD(&ctx, D0, 0, A0);
+///
+/// if (error) <. . . Handle assembly error based on ctx->error>
+/// rc = pore_inline_branch_fixup(&ctx, source, target);
+/// if (rc) <. . . Handle branch fixup error>
+///
+/// \endcode
+///
+/// In the above code, the branch instruction is initially assembled as a
+/// branch-to-self - the recommended idiom for forward branch source
+/// instructions. Once the entire sequence has been assembled,
+/// pore_inline_branch_fixup() reassembles the \c source instruction as a
+/// branch to the \c target instruction. The above instruction sequence is
+/// equivalent to the PGAS code below:
+///
+/// \code
+///
+/// source:
+/// branz D0, target
+/// adds D1, D1, 1
+/// target:
+/// ld D0, 0, A0
+///
+/// \endcode
+///
+///
+/// \subsubsection Absolute Branches
+///
+/// It is unlikely that a typical application of the PORE inline assembler
+/// would ever need to include an absolute branch, since the branch target in
+/// this case is a fixed absolute address that must be known at assembly
+/// time. However the inline assembler does provide the pore_BRAIA() API for
+/// this purpose. This opcode requires a 16-bit address space constant and a
+/// 32-bit absoulte address (offset) within the memory space to specify the
+/// branch.
+///
+///
+/// \section Disassembly
+///
+/// Inline disassembly is implemented by a single API,
+/// pore_inline_disassemble(). The idea is similar to assembly: A host memory
+/// context containing PORE code (or data) is described by a PoreInlineContext
+/// structure. Each call of pore_inline_disassemble() disassembles the next
+/// instruction (or datum) in the context into a PoreInlineDisassembly
+/// structure provided by the caller. The disassembly object contains both
+/// binary and string forms of the disassembled instruction (or data). The
+/// next call of pore_inline_disassemble() proceses the next instruction (or
+/// datum) and so on.
+///
+/// \subsection Text (Code) Disassembly
+///
+/// In the example below the inline disassembler is used to completely
+/// disassemble a memory area containing text (code) to \a stdout until an
+/// error occurs, assumed to be either due to disassembling the entire memory
+/// area or finding an illegal instruction.
+///
+/// \code
+///
+/// PoreInlineContext ctx;
+/// PoreInlineDisassembly dis;
+///
+/// . . . // Initialize context
+///
+/// while (pore_inline_disassemble(&ctx, &dis) == 0) {
+/// printf("%s\n", dis.s);
+/// }
+///
+/// \endcode
+///
+/// To illustrate binary disassembly, the following example uses the
+/// disassembler to search for a RET statement in a block of PORE code, in
+/// order to extend an inline subroutine with more code. Note that the field
+/// \a dis->ctx contains the context that existed at the time the instruction
+/// was assembled. By copying this context back into the global context,
+/// inline assembly will continue by overwriting the RET with new
+/// instructions. If the copy had \e not been done, then newly assembled code
+/// would have \e followed the RET.
+///
+/// \code
+///
+/// PoreInlineContext ctx;
+/// PoreInlineDisassembly dis;
+///
+/// . . . // Initialize context
+///
+/// while ((pore_inline_disassemble(&ctx, &dis) == 0) &&
+/// (dis.opcode != PORE_OPCODE_RET));
+/// if (ctx.error != 0) {
+/// . . . // Handle error
+/// } else {
+/// pore_inline_context_copy(&ctx, &dis.ctx);
+/// . . . // Continue assembly by overwriting the RET
+/// }
+///
+/// \endcode
+///
+/// A special type of context reset is available to simplify applications that
+/// need to disassemble a just-assembled code sequence, e.g. for debugging.
+/// pore_inline_context_reset_excursion() resets the context such that the
+/// effective size of the context only covers the just-assembled code,
+/// allowing a dissassembly loop to cleanly stop once all code has been
+/// disassembled. The use is illustrated below - note that the disassembly
+/// stops on the expected error code PORE_INLINE_NO_MEMORY once the
+/// (effective) end of the buffer is reached.
+///
+/// \code
+///
+/// PoreInlineContext ctx;
+/// PoreInlineDisassembly dis;
+///
+/// . . . // Initialize context
+/// . . . // Assemble code into context
+///
+/// pore_inline_context_reset_excursion(&ctx);
+///
+/// while (pore_inline_disassemble(&ctx, &dis) == 0) {
+/// printf("%s\n", dis.s);
+/// }
+/// if (ctx.error != PORE_INLINE_NO_MEMORY) {
+/// . . . // Handle error
+/// }
+///
+/// \endcode
+///
+/// \subsection Data Disassembly
+///
+/// If the PoreInlineContext is created with the flag
+/// PORE_INLINE_DISASSEMBLE_DATA, then the context is disassembled as data. If
+/// the PoreInlineContext is created with the flag
+/// PORE_INLINE_DISASSEMBLE_UNKNOWN then putative data embedded in a text
+/// section will be disassembled as data. For complete information see the
+/// documentation for pore_inline_disassemble().
+
+
+#define __PORE_INLINE_ASSEMBLER_C__
+#include "pore_inline.h"
+#undef __PORE_INLINE_ASSEMBLER_C__
+
+// Definitions of PORE register classes. These are predicates that return
+// 1 if the register is a member of the class, else 0.
+
+PORE_STATIC int
+pore_data(int reg)
+{
+ return
+ (reg == D0) ||
+ (reg == D1);
+}
+
+
+PORE_STATIC int
+pore_address(int reg)
+{
+ return
+ (reg == A0) ||
+ (reg == A1);
+}
+
+
+PORE_STATIC int
+pore_pervasive_chiplet_id(int reg)
+{
+ return
+ (reg == P0) ||
+ (reg == P1);
+}
+
+
+PORE_STATIC int
+pore_branch_compare_data(int reg)
+{
+ return
+ (reg == D0) ||
+ (reg == D1) ||
+ (reg == CTR);
+}
+
+
+PORE_STATIC int
+pore_ls_destination(int reg)
+{
+ return
+ (reg == D0) ||
+ (reg == D1) ||
+ (reg == A0) ||
+ (reg == A1) ||
+ (reg == P0) ||
+ (reg == P1) ||
+ (reg == CTR);
+}
+
+
+PORE_STATIC int
+pore_li_destination(int reg)
+{
+ return
+ (reg == D0) ||
+ (reg == D1) ||
+ (reg == A0) ||
+ (reg == A1) ||
+ (reg == P0) ||
+ (reg == P1) ||
+ (reg == CTR);
+}
+
+
+PORE_STATIC int
+pore_mr_source(int reg)
+{
+ return
+ (reg == D0) ||
+ (reg == D1) ||
+ (reg == A0) ||
+ (reg == A1) ||
+ (reg == P0) ||
+ (reg == P1) ||
+ (reg == CTR) ||
+ (reg == PC) ||
+ (reg == ETR) ||
+ (reg == SPRG0) ||
+ (reg == IFR) ||
+ (reg == EMR);
+}
+
+PORE_STATIC int
+pore_mr_destination(int reg)
+{
+ return
+ (reg == D0) ||
+ (reg == D1) ||
+ (reg == A0) ||
+ (reg == A1) ||
+ (reg == P0) ||
+ (reg == P1) ||
+ (reg == CTR) ||
+ (reg == PC) ||
+ (reg == SPRG0)||
+ (reg == EMR);
+}
+
+
+/// Portable store of a 32-bit integer in big-endian format
+///
+/// The address \a p to receive the data is in the form of an unsigned long.
+
+void
+pore_inline_be32(unsigned long p, uint32_t x)
+{
+ uint8_t *p8 = (uint8_t *)p;
+ uint8_t *px = (uint8_t *)(&x);
+ int i, j;
+
+ if (!PORE_BIG_ENDIAN) {
+ for (i = 0, j = 3; i < 4; i++, j--) {
+ p8[i] = px[j];
+ }
+ } else {
+ *((uint32_t *)p) = x;
+ }
+}
+
+
+/// Portable store of a 64-bit integer in big-endian format
+///
+/// The address \a p to receive the data is in the form of an unsigned long.
+
+void
+pore_inline_be64(unsigned long p, uint64_t x)
+{
+ uint8_t *p8 = (uint8_t *)p;
+ uint8_t *px = (uint8_t *)(&x);
+ int i, j;
+
+ if (!PORE_BIG_ENDIAN) {
+ for (i = 0, j = 7; i < 8; i++, j--) {
+ p8[i] = px[j];
+ }
+ } else {
+ *((uint64_t *)p) = x;
+ }
+}
+
+
+// Portable load of a 32-bit integer in big-endian format
+
+uint32_t
+pore_inline_host32(unsigned long p)
+{
+ uint32_t x;
+ uint8_t *p8 = (uint8_t *)p;
+ uint8_t *px = (uint8_t *)(&x);
+ int i, j;
+
+ if (!PORE_BIG_ENDIAN) {
+ for (i = 0, j = 3; i < 4; i++, j--) {
+ px[j] = p8[i];
+ }
+ } else {
+ x = *((uint32_t *)p);
+ }
+
+ return x;
+}
+
+
+// Portable load of a 64-bit integer in big-endian format
+
+uint64_t
+pore_inline_host64(unsigned long p)
+{
+ uint64_t x;
+ uint8_t *p8 = (uint8_t *)p;
+ uint8_t *px = (uint8_t *)(&x);
+ int i, j;
+
+ if (!PORE_BIG_ENDIAN) {
+ for (i = 0, j = 7; i < 8; i++, j--) {
+ px[j] = p8[i];
+ }
+ } else {
+ x = *((uint64_t *)p);
+ }
+
+ return x;
+}
+
+
+// 32-bit population count
+//
+// This is a well-known divide-and-conquer algorithm. The idea is to compute
+// sums of adjacent bit segments in parallel, in place.
+
+PORE_STATIC int
+pore_popcount32(uint32_t x)
+{
+ uint32_t m1 = 0x55555555;
+ uint32_t m2 = 0x33333333;
+ uint32_t m4 = 0x0f0f0f0f;
+ x -= (x >> 1) & m1; /* Sum pairs of bits */
+ x = (x & m2) + ((x >> 2) & m2);/* Sum 4-bit segments */
+ x = (x + (x >> 4)) & m4; /* Sum 8-bit segments */
+ x += x >> 8; /* Sum 16-bit segments */
+ return (x + (x >> 16)) & 0x3f; /* Final sum */
+}
+
+
+// 64-bit population count
+
+PORE_STATIC int
+pore_popcount64(uint64_t x)
+{
+ return pore_popcount32(x & 0xffffffff) + pore_popcount32(x >> 32);
+}
+
+
+// Compute the parity of a PORE instruction as 0 or 1
+
+int
+pore_inline_parity(uint32_t instruction, uint64_t imd64)
+{
+ return (pore_popcount32(instruction) + pore_popcount64(imd64)) % 2;
+}
+
+
+/// Reset a PORE inline assembler context to its creation state
+///
+/// \param ctx A pointer to an initialized (and likely 'used')
+/// PoreInlineContext object.
+///
+/// This API resets a PoreInlineContext object to it's \e creation state, that
+/// is, the state it was in after the call of pore_inline_context_create().
+/// This API is designed for applications that reuse a memory buffer to
+/// assemble multiple PORE code sequences. After each sequence has been fully
+/// assembled and processed, calling pore_inline_context_reset() sets the
+/// context back as it was when the context was initially created so that the
+/// memory area can be reused. In particular, this API resets the location
+/// counter and memory extent to their initial values, and the error code is
+/// cleared. Any options specified at creation remain as they were.
+///
+/// For a slightly different type of reset, see
+/// pore_inline_context_reset_excursion().
+
+void
+pore_inline_context_reset(PoreInlineContext *ctx)
+{
+ ctx->lc_address = ctx->memory;
+ ctx->remaining = ctx->size;
+ ctx->lc = ctx->original_lc;
+ ctx->error = 0;
+}
+
+
+
+/// Reset a PORE inline assembler context to a special state for disassembly
+///
+/// \param ctx A pointer to an initialized (and almost certainly 'used')
+/// PoreInlineContext object.
+///
+/// This API resets a PoreInlineContext object to it's \e creation state, that
+/// is, the state it was in after the call of pore_inline_context_create(), \e
+/// except that the effective size of the memory area has been reduced to the
+/// size that was actually used during assembly. This API is designed for
+/// applications that assemble into a memory buffer and then want to easily
+/// disassemble the code (e.g., for debugging). After a code sequence has
+/// been assembled, calling pore_inline_context_reset_excursion() sets the
+/// context back as it was when the context was initially created, but with a
+/// (typically) shorter effective length, so that the disassembly will cleanly
+/// stop once the entire sequence has been disassembled. Once disassembled,
+/// the buffer can be fully resued after a subsequent call of
+/// pore_inline_context_reset(). In particular, this API resets the location
+/// counter to its initial value, clears the error code, and sets the
+/// effective size of the context to the amount of memory currently used. Any
+/// options specified at creation remain as they were.
+///
+/// For a full context reset see pore_inline_context_reset(). For an example
+/// see the \b Disassembly section of \ref pore_inline_assembler.
+
+void
+pore_inline_context_reset_excursion(PoreInlineContext *ctx)
+{
+ ctx->lc_address = ctx->memory;
+ ctx->remaining = ctx->size - ctx->remaining;
+ ctx->lc = ctx->original_lc;
+ ctx->error = 0;
+}
+
+
+/// Create a PORE inline assembler context
+///
+/// \param ctx A pointer to a PoreInlineContext object to be initialized
+/// and used for inline assembly. or disassembly.
+///
+/// \param memory A pointer to the host memory area to receive the assembled
+/// code, or contain the code to disassemble. In general the inline assembler
+/// will expect this memory area to be 4-byte aligned. This pointer may be
+/// NULL (0) only if the associated \a size is also 0.
+///
+/// \param size The size (in bytes) of the host memory area. The inline
+/// assembler will generate the PORE_INLINE_NO_MEMORY error if an attempt is
+/// made to assemble an instruction that would overflow the buffer, or
+/// disassemble past the end of the buffer. A 0 size is valid.
+///
+/// \param lc The initial, bytewise, target location counter for the assembled
+/// or disassembled code. This paramater will normally be initialized to 0 for
+/// assembling relocatable programs. The parameter would only need to be
+/// specified as non-0 for special cases, such as creating a context for
+/// disassembly.
+///
+/// \param options Option flags. Option flags are OR-ed together to create
+/// the final set of options. Valid options are
+///
+/// - PORE_INLINE_GENERATE_PARITY : Generate the proper parity bit for each
+/// instruction during assembly.
+///
+/// - PORE_INLINE_CHECK_PARITY : Check for correct instruction parity during
+/// disassembly.
+///
+/// - PORE_INLINE_LISTING_MODE : Generate disassembly strings in the form of a
+/// listing that contains location counters and encoded instructions as well
+/// as their diassembly. By default the disassembly strings do not contain
+/// this information and can be fed back in as source code to a PORE
+/// assembler.
+///
+/// - PORE_INLINE_DISASSEMBLE_DATA : generate disassembly assuming that the
+/// context contains data rather than text. Normally data is disassembled as
+/// .long directives, however if the context is unaligned or of an odd length
+/// then .byte directives may be used as well. This option can be used in
+/// conjunction with PORE_INLINE_LISTING_MODE.
+///
+/// - PORE_INLINE_8_BYTE_DATA : generate data disassembly using 8-byte values
+/// rather than the default 4-byte values. Normally data is disassembled as
+/// .quad directives under this option, however if the context is unaligned or
+/// of an odd length then .long and .byte directives may be used as well.
+/// This option can be used in conjunction with PORE_INLINE_LISTING_MODE.
+///
+/// A PoreInlineContext describes a memory area and assembler context for
+/// inline assembly and disassembly. Assembly/disassembly begins at the host
+/// memory location and virtual location counter described in the parameters.
+/// As instructions are assembled/disassembled the PoreInlineContext keeps
+/// track of where in the host memory and virtual PORE memory areas to place
+/// new instructions during assembly, or from where to fetch the next
+/// instruction to disassemble.
+///
+/// \retval 0 Success
+///
+/// \retval PORE_INLINE_INVALID_PARAMETER Either the \a context pointer is
+/// NULL (0), the \a memory pointer is NULL (0) with a non-0 size, or the \a
+/// options include invalid options. The error code is also stored as the
+/// value of ctx->error, and in the event of an error the ctx->size field is
+/// set to 0, effectively preventing the context from being used.
+
+int
+pore_inline_context_create(PoreInlineContext *ctx,
+ void *memory, size_t size,
+ PoreInlineLocation lc, int options)
+{
+ int rc;
+
+ int valid_options =
+ PORE_INLINE_GENERATE_PARITY |
+ PORE_INLINE_CHECK_PARITY |
+ PORE_INLINE_LISTING_MODE |
+ PORE_INLINE_DISASSEMBLE_DATA |
+ PORE_INLINE_8_BYTE_DATA |
+ PORE_INLINE_DISASSEMBLE_UNKNOWN;
+
+ if ((ctx == NULL) || ((memory == NULL) && (size != 0)) ||
+ ((options & ~valid_options) != 0)) {
+ rc = PORE_INLINE_INVALID_PARAMETER;
+ } else {
+ rc = 0;
+ ctx->memory = (unsigned long)memory;
+ ctx->size = size;
+ ctx->original_lc = lc;
+ ctx->options = options;
+ pore_inline_context_reset(ctx);
+ }
+
+ if (ctx != NULL) {
+ ctx->error = rc;
+ if (rc) {
+ ctx->size = 0; /* Effectively prevents using the ctx */
+ }
+ }
+
+ return rc;
+}
+
+
+/// Copy a PORE inline assembler context
+///
+/// \param dest A pointer to a PoreInlineContext object to be initialized
+/// as a copy of the \a src context.
+///
+/// \param src A pointer to a PoreInlineContext object to be used as the
+/// source of the copy.
+///
+/// This API copies one PoreInlineContext structure to another. An example
+/// use appears in \ref pore_inline_assembler in the section discussing
+/// disassembly.
+
+void
+pore_inline_context_copy(PoreInlineContext *dest, PoreInlineContext *src)
+{
+ *dest = *src;
+}
+
+
+// 'Bump' a context forward by a given number of bytes. This an internal API
+// and the bump is always known to be legal.
+
+void
+pore_inline_context_bump(PoreInlineContext *ctx, size_t bytes)
+{
+ ctx->remaining -= bytes;
+ ctx->lc += bytes;
+ ctx->lc_address += bytes;
+}
+
+
+// Allocate space in the inline assembler context
+//
+// Allocation is specified and implemented in bytes. Both the physical
+// memory and the virtual LC are required to be 4-byte aligned. The allocator
+// returns a pointer to the memory area, or 0 if allocation fails.
+// Allocation failure sets the context error code to either
+// PORE_INLINE_NO_MEMORY or PORE_INLINE_ALIGNMENT_ERROR.
+
+PORE_STATIC unsigned long
+pore_inline_allocate(PoreInlineContext *ctx, size_t bytes)
+{
+ unsigned long p = 0;
+
+ if (((ctx->lc % 4) != 0) ||
+ ((ctx->lc_address % 4) != 0)) {
+ ctx->error = PORE_INLINE_ALIGNMENT_ERROR;
+
+ } else if (bytes > ctx->remaining) {
+ ctx->error = PORE_INLINE_NO_MEMORY;
+
+ } else {
+ p = ctx->lc_address;
+ pore_inline_context_bump(ctx, bytes);
+ }
+ return p;
+}
+
+
+// Assemble a 1-word instruction
+//
+// The opcode and operand are assumed to be legal, having come from
+// abstractions that check their arguments. This call may fail with
+// PORE_INLINE_NO_MEMORY if there is no more room in the memory buffer. A
+// non-zero return indicates failure.
+
+int
+pore_inline_instruction1(PoreInlineContext *ctx, int opcode, uint32_t operand)
+{
+ uint32_t instruction;
+ unsigned long p;
+
+ p = pore_inline_allocate(ctx, 4);
+ if (p != 0) {
+
+ instruction = (opcode << 25) | operand;
+ if (ctx->options & PORE_INLINE_GENERATE_PARITY) {
+ instruction |= (1 - pore_inline_parity(instruction, 0)) << 24;
+ }
+
+ pore_inline_be32(p, instruction);
+ ctx->error = 0;
+ }
+ return p == 0;
+}
+
+
+// Assemble a 3-word instruction
+//
+// The opcode and operand are assumed to be legal, having come from
+// abstractions that check their arguments. This call may fail with
+// PORE_INLINE_NO_MEMORY if there is no more room in the memory buffer. A
+// non-zero return indicates failure.
+
+int
+pore_inline_instruction3(PoreInlineContext *ctx, int opcode, uint32_t operand,
+ uint64_t immediate)
+{
+ uint32_t instruction;
+ unsigned long p;
+
+ p = pore_inline_allocate(ctx, 12);
+ if (p != 0) {
+
+ instruction = (opcode << 25) | operand;
+ if (ctx->options & PORE_INLINE_GENERATE_PARITY) {
+ instruction |= (1 - pore_inline_parity(instruction, immediate)) << 24;
+ }
+
+ pore_inline_be32(p, instruction);
+ pore_inline_be64(p + 4, immediate);
+ ctx->error = 0;
+ }
+ return p == 0;
+}
+
+
+// Assemble WAIT
+//
+// The cycle count must be an unsigned 24-bit immediate otherwise the error
+// PORE_INLINE_UINT24_REQUIRED is signalled. PGAS requires that HALT be used
+// if the intention is to halt
+
+int
+pore_WAITS(PoreInlineContext *ctx, uint32_t cycles)
+{
+ uint32_t operand;
+ int opcode = PGAS_OPCODE_WAITS;
+
+ if (cycles == 0) {
+ ctx->error = PORE_INLINE_USE_HALT;
+ } else if ((cycles & 0xffffff) != cycles) {
+ ctx->error = PORE_INLINE_UINT24_REQUIRED;
+ } else {
+ operand = cycles;
+ pore_inline_instruction1(ctx, opcode, operand);
+ }
+ return ctx->error;
+}
+
+
+// Assemble HOOKI
+//
+// The hook index must be an unsigned 24-bit immediate otherwise the error
+// PORE_INLINE_UINT24_REQUIRED is signalled.
+
+int
+pore_HOOKI(PoreInlineContext *ctx, uint32_t index, uint64_t imm)
+{
+ uint32_t operand;
+ int opcode = PGAS_OPCODE_HOOKI;
+
+ if ((index & 0xffffff) != index) {
+ ctx->error = PORE_INLINE_UINT24_REQUIRED;
+ } else {
+ operand = index;
+ pore_inline_instruction3(ctx, opcode, operand, imm);
+ }
+ return ctx->error;
+}
+
+
+// Assemble BRA, BSR and LOOP
+//
+// The branch target here is a bytewise location counter. The target must be
+// 4-byte aligned and must be within the legal signed 24-bit word offset of
+// the current LC. Unaligned targets cause PORE_INLINE_ALIGNMENT_ERROR.
+// Unreachable targets cause PORE_INLINE_UNREACHABLE_TARGET.
+
+int
+pore_inline_bra(PoreInlineContext *ctx, int opcode, PoreInlineLocation target)
+{
+ int32_t offset;
+ uint32_t operand;
+
+ if (target % 4) {
+ ctx->error = PORE_INLINE_ALIGNMENT_ERROR;
+ } else {
+ offset = (int32_t)(target - ctx->lc) / 4;
+ if ((offset >= (1 << 23)) ||
+ (offset < -(1 << 23))) {
+ ctx->error = PORE_INLINE_UNREACHABLE_TARGET;
+ } else {
+ operand = offset & 0xffffff;
+ pore_inline_instruction1(ctx, opcode, operand);
+ }
+ }
+ return ctx->error;
+}
+
+
+// Assemble BRAZ and BRANZ
+//
+// The branch target here is a bytewise location counter. The target must be
+// 4-byte aligned and must be within the legal signed 20-bit word offset of
+// the current LC. Unaligned targets cause PORE_INLINE_ALIGNMENT_ERROR.
+// Unreachable targets cause PORE_INLINE_UNREACHABLE_TARGET. Illegal
+// operands cause PORE_INLINE_ILLEGAL_REGISTER.
+
+int
+pore_inline_brac(PoreInlineContext *ctx, int opcode, int reg,
+ PoreInlineLocation target)
+{
+ int32_t offset;
+ uint32_t operand;
+
+ if (target % 4) {
+ ctx->error = PORE_INLINE_ALIGNMENT_ERROR;
+ } else if (!pore_branch_compare_data(reg)) {
+ ctx->error = PORE_INLINE_ILLEGAL_REGISTER;
+ } else {
+ offset = (int32_t)(target - ctx->lc) / 4;
+ if ((offset >= (1 << 20)) ||
+ (offset < -(1 << 20))) {
+ ctx->error = PORE_INLINE_UNREACHABLE_TARGET;
+ } else {
+ operand = (offset & 0xfffff) | (reg << 20);
+ pore_inline_instruction1(ctx, opcode, operand);
+ }
+ }
+ return ctx->error;
+}
+
+
+// Assemble CMPIBRAEQ, CMPIBRANE, CMPIBSREQ
+//
+// The branch target here is a bytewise location counter. The target must be
+// 4-byte aligned and must be within the legal signed 24-bit word offset of
+// the current LC. Unaligned targets cause PORE_INLINE_ALIGNMENT_ERROR.
+// Unreachable targets cause PORE_INLINE_UNREACHABLE_TARGET. Illegal
+// operands cause PORE_INLINE_ILLEGAL_REGISTER.
+
+int
+pore_inline_cmpibra(PoreInlineContext *ctx, int opcode, int reg,
+ PoreInlineLocation target, uint64_t imm)
+{
+ int32_t offset;
+ uint32_t operand;
+
+ if (target % 4) {
+ ctx->error = PORE_INLINE_ALIGNMENT_ERROR;
+ } else if (reg != D0) {
+ ctx->error = PORE_INLINE_ILLEGAL_REGISTER;
+ } else {
+ offset = (int32_t)(target - ctx->lc) / 4;
+ if ((offset >= (1 << 23)) ||
+ (offset < -(1 << 23))) {
+ ctx->error = PORE_INLINE_UNREACHABLE_TARGET;
+ } else {
+ operand = offset & 0xffffff;
+ pore_inline_instruction3(ctx, opcode, operand, imm);
+ }
+ }
+ return ctx->error;
+}
+
+
+// Assemble BRAD and BSRD
+//
+// Illegal operands cause PORE_INLINE_ILLEGAL_REGISTER.
+
+int
+pore_inline_brad(PoreInlineContext *ctx, int opcode, int reg)
+{
+ uint32_t operand;
+
+ if (!pore_data(reg)) {
+ ctx->error = PORE_INLINE_ILLEGAL_REGISTER;
+ } else {
+ operand = reg << 20;
+ pore_inline_instruction1(ctx, opcode, operand);
+ }
+ return ctx->error;
+}
+
+
+// Assemble ANDI, ORI, XORI
+//
+// Source and destination must be of class 'data' otherwise the
+// PORE_INLINE_ILLEGAL_REGISTER error is generated.
+
+int
+pore_inline_ilogic(PoreInlineContext *ctx, int opcode,
+ int dest, int src, uint64_t imm)
+{
+ uint32_t operand;
+
+ if (!pore_data(dest) || !pore_data(src)) {
+ ctx->error = PORE_INLINE_ILLEGAL_REGISTER;
+ } else {
+ operand = (dest << 20) | (src << 16);
+ pore_inline_instruction3(ctx, opcode, operand, imm);
+ }
+ return ctx->error;
+}
+
+
+// Assemble AND, OR, XOR, ADD, SUB
+//
+// Destination must be of class 'data' otherwise the
+// PORE_INLINE_ILLEGAL_REGISTER error is generated. src1 and src2 must be D0,
+// D1 respectively otherwise the PORE_INLINE_ILLEGAL_REGISTER error is
+// generated.
+
+int
+pore_inline_alurr(PoreInlineContext *ctx,
+ int opcode, int dest, int src1, int src2)
+{
+ uint32_t operand;
+
+ if (!pore_data(dest) || (src1 != D0) || (src2 != D1)) {
+ ctx->error = PORE_INLINE_ILLEGAL_REGISTER;
+ } else {
+ operand = (dest << 20);
+ pore_inline_instruction1(ctx, opcode, operand);
+ }
+ return ctx->error;
+}
+
+
+// Assemble ADDS and SUBS
+//
+// Destination must be of class 'ls_destination' and must be equal to source,
+// otherwise the PORE_INLINE_ILLEGAL_REGISTER error is generated. If the
+// immediate is not a signed 16-bit immediate then the
+// PORE_INLINE_INT16_REQUIRED error is generated.
+
+int
+pore_inline_adds(PoreInlineContext *ctx,
+ int opcode, int dest, int src, int imm)
+{
+ uint32_t operand;
+
+ if (!pore_ls_destination(dest) || (dest != src)) {
+ ctx->error = PORE_INLINE_ILLEGAL_REGISTER;
+ } else {
+ if ((imm >= (1 << 15)) ||
+ (imm < -(1 << 15))) {
+ ctx->error = PORE_INLINE_INT16_REQUIRED;
+ } else {
+ operand = (dest << 20) | (imm & 0xffff);
+ pore_inline_instruction1(ctx, opcode, operand);
+ }
+ }
+ return ctx->error;
+}
+
+
+// Assemble NEG
+//
+// Source and destination must be of class 'data' otherwise the
+// PORE_INLINE_ILLEGAL_REGISTER error is generated.
+
+int
+pore_NEG(PoreInlineContext *ctx, int dest, int src)
+{
+ uint32_t operand;
+ int opcode = PGAS_OPCODE_NEG;
+
+ if (!pore_data(dest) || !pore_data(src)) {
+ ctx->error = PORE_INLINE_ILLEGAL_REGISTER;
+ } else {
+ operand = (dest << 20) | (src << 16);
+ pore_inline_instruction1(ctx, opcode, operand);
+ }
+ return ctx->error;
+}
+
+
+// Assemble MR
+//
+// The source must be an 'mr_source' and the destination must be an
+// 'mr_destination' otherwise the PORE_INLINE_ILLEGAL_REGISTER error is
+// generated.
+
+int
+pore_MR(PoreInlineContext *ctx, int dest, int src)
+{
+ uint32_t operand;
+ int opcode = PGAS_OPCODE_MR;
+
+ if (!pore_mr_destination(dest) || !pore_mr_source(src)) {
+ ctx->error = PORE_INLINE_ILLEGAL_REGISTER;
+ } else {
+ operand = (dest << 20) | (src << 16);
+ pore_inline_instruction1(ctx, opcode, operand);
+ }
+ return ctx->error;
+}
+
+
+
+// Assemble ROLS
+//
+// Source and destination must be of class 'data' otherwise the
+// PORE_INLINE_ILLEGAL_REGISTER error is generated. Illegal shifts yield the
+// PORE_INLINE_ILLEGAL_ROTATE error.
+
+int
+pore_ROLS(PoreInlineContext *ctx, int dest, int src, int imm)
+{
+ uint32_t operand;
+ int opcode = PGAS_OPCODE_ROLS;
+
+ if (!pore_data(dest) || !pore_data(src)) {
+ ctx->error = PORE_INLINE_ILLEGAL_REGISTER;
+ } else if ((imm != 1) &&
+ (imm != 4) &&
+ (imm != 8) &&
+ (imm != 16) &&
+ (imm != 32)) {
+ ctx->error = PORE_INLINE_ILLEGAL_ROTATE;
+ } else {
+ operand = (dest << 20) | (src << 16) | imm;
+ pore_inline_instruction1(ctx, opcode, operand);
+ }
+ return ctx->error;
+}
+
+
+// Assemble LS
+//
+// The destination must be an 'ls_destination' otherwise the
+// PORE_INLINE_ILLEGAL_REGISTER error is generated. If the immediate is not
+// a signed 20-bit immediate then the PORE_INLINE_INT20_REQUIRED error is
+// generated.
+
+int
+pore_LS(PoreInlineContext *ctx, int dest, int imm)
+{
+ uint32_t operand;
+ int opcode = PGAS_OPCODE_LS;
+
+ if (!pore_ls_destination(dest)) {
+ ctx->error = PORE_INLINE_ILLEGAL_REGISTER;
+ } else if ((imm >= (1 << 19)) ||
+ (imm < -(1 << 19))) {
+ ctx->error = PORE_INLINE_INT20_REQUIRED;
+ } else {
+ operand = (dest << 20) | (imm & 0xfffff);
+ pore_inline_instruction1(ctx, opcode, operand);
+ }
+ return ctx->error;
+}
+
+
+// Assemble LI
+//
+// The destination must be an 'li destination' otherwise the
+// PORE_INLINE_ILLEGAL_REGISTER error is generated.
+
+int
+pore_LI(PoreInlineContext *ctx, int dest, uint64_t imm)
+{
+ uint32_t operand;
+ int opcode = PGAS_OPCODE_LI;
+
+ if (!pore_li_destination(dest)) {
+ ctx->error = PORE_INLINE_ILLEGAL_REGISTER;
+ } else {
+ operand = dest << 20;
+ pore_inline_instruction3(ctx, opcode, operand, imm);
+ }
+ return ctx->error;
+}
+
+
+// BSI and BCI are normally redacted as instructions due to HW274735
+
+// LD, LDANDI, STD, STI, BSI, BCI
+
+PORE_STATIC void
+pervasive_ima24(PoreInlineContext *ctx,
+ int opcode, uint32_t offset, int base, uint64_t imm)
+{
+ uint32_t operand;
+
+ if ((offset & 0x80f00000) != 0) {
+ ctx->error = PORE_INLINE_ILLEGAL_SCOM_ADDRESS;
+ } else {
+ operand = ((base % 2) << 22) | (offset & 0xfffff);
+ switch (opcode) {
+ case PGAS_OPCODE_LD0:
+ case PGAS_OPCODE_LD1:
+ case PGAS_OPCODE_STD0:
+ case PGAS_OPCODE_STD1:
+ pore_inline_instruction1(ctx, opcode, operand);
+ break;
+ default:
+ pore_inline_instruction3(ctx, opcode, operand, imm);
+ break;
+ }
+ }
+}
+
+
+PORE_STATIC void
+memory_ima24(PoreInlineContext *ctx,
+ int opcode, uint32_t offset, int base, uint64_t imm)
+{
+ uint32_t operand;
+
+ if ((offset & 0x3fffff) != offset) {
+ ctx->error = PORE_INLINE_UINT22_REQUIRED;
+ } else if ((offset % 8) != 0) {
+ ctx->error = PORE_INLINE_ALIGNMENT_ERROR;
+ } else {
+ operand = 0x800000 | ((base % 2) << 22) | (offset & 0x3fffff);
+ switch (opcode) {
+ case PGAS_OPCODE_LD0:
+ case PGAS_OPCODE_LD1:
+ case PGAS_OPCODE_STD0:
+ case PGAS_OPCODE_STD1:
+ pore_inline_instruction1(ctx, opcode, operand);
+ break;
+ default:
+ pore_inline_instruction3(ctx, opcode, operand, imm);
+ break;
+ }
+ }
+}
+
+
+PORE_STATIC void
+ima24(PoreInlineContext *ctx,
+ int opcode, uint32_t offset, int base, uint64_t imm)
+{
+ if (pore_pervasive_chiplet_id(base)) {
+ pervasive_ima24(ctx, opcode, offset, base, imm);
+ } else if (pore_address(base)) {
+ memory_ima24(ctx, opcode, offset, base, imm);
+ } else {
+ ctx->error = PORE_INLINE_ILLEGAL_REGISTER;
+ }
+}
+
+
+int
+pore_inline_load_store(PoreInlineContext *ctx,
+ int opcode, int src_dest, int32_t offset, int base,
+ uint64_t imm)
+{
+ switch (opcode) {
+
+ case PORE_INLINE_PSEUDO_LD:
+ case PORE_INLINE_PSEUDO_LDANDI:
+ case PORE_INLINE_PSEUDO_STD:
+
+ // These three pick the real opcode based on the dest. register
+
+ if (!pore_data(src_dest)) {
+ ctx->error = PORE_INLINE_ILLEGAL_REGISTER;
+ } else {
+ switch (opcode) {
+ case PORE_INLINE_PSEUDO_LD:
+ opcode = (src_dest == D0) ?
+ PGAS_OPCODE_LD0 : PGAS_OPCODE_LD1;
+ break;
+ case PORE_INLINE_PSEUDO_LDANDI:
+ opcode = (src_dest == D0) ?
+ PGAS_OPCODE_LD0ANDI : PGAS_OPCODE_LD1ANDI;
+ break;
+ case PORE_INLINE_PSEUDO_STD:
+ opcode = (src_dest == D0) ?
+ PGAS_OPCODE_STD0 : PGAS_OPCODE_STD1;
+ break;
+ }
+ }
+ break;
+
+#ifdef IGNORE_HW274735
+
+ // BSI and BCI are normally redacted as instructions due to HW274735
+
+ case PGAS_OPCODE_BSI:
+ case PGAS_OPCODE_BCI:
+
+ if (src_dest != D0) {
+ ctx->error = PORE_INLINE_ILLEGAL_REGISTER;
+ }
+ break;
+
+#endif // IGNORE_HW274735
+
+ case PGAS_OPCODE_STI:
+ break;
+
+ default:
+ ctx->error = PORE_INLINE_BUG;
+ }
+
+ if (ctx->error == 0) {
+ ima24(ctx, opcode, offset, base, imm);
+ }
+
+ return ctx->error;
+}
+
+
+// Assemble BRAIA
+
+int
+pore_BRAIA(PoreInlineContext *ctx,
+ uint16_t address_space, uint32_t offset)
+{
+ int opcode = PGAS_OPCODE_BRAI;
+ uint32_t operand = 0;
+ uint64_t imm = ((uint64_t)address_space << 32) | offset;
+
+ pore_inline_instruction3(ctx, opcode, operand, imm);
+
+ return ctx->error;
+}
+
+
+// Assemble SCAND
+
+int
+pore_SCAND(PoreInlineContext *ctx,
+ int update, int capture, uint16_t length,
+ uint32_t select, uint32_t offset)
+{
+ int opcode = PGAS_OPCODE_SCAND;
+ uint32_t operand;
+ uint64_t imm = ((uint64_t)select << 32) | offset;
+
+ if ((update < 0) ||
+ (update > 1) ||
+ (capture < 0) ||
+ (capture > 1)) {
+ ctx->error = PORE_INLINE_INVALID_PARAMETER;
+ } else {
+ opcode = PGAS_OPCODE_SCAND;
+ operand = (update << 23) | (capture << 22) | length;
+ pore_inline_instruction3(ctx, opcode, operand, imm);
+ }
+ return ctx->error;
+}
+
+
+/// Fix up a PORE inline assembler forward branch instruction
+///
+/// \param ctx A pointer to the initialized PoreInlineContext object
+/// controlling inline assembly.
+///
+/// \param source The PORE inline location counter associated with the source
+/// instruction of the forward branch.
+///
+/// \param target The PORE inline location counter associated with the target
+/// instruction of the forward branch.
+///
+/// For usage examples, see the documentation \ref pore_inline_assembler.
+/// Although intended for forward branches, this API could be used to create
+/// backward branches as well. Note however the limitation that the \a source
+/// must be in the current context, since the source instruction needs to be
+/// reassembled with the branch target. In theory the \a target could be
+/// anywhere, as long as the location counter of the target is known.
+///
+/// \retval 0 Success
+///
+/// \retval code Failure. Any non-zero return is the PORE inline assmebler
+/// error code. The failure code is also stored in the PoreInlineContext
+/// object \a error field. The most likely causes of failure include a source
+/// location that is not in the current context or not associated with a
+/// branch instruction.
+
+int
+pore_inline_branch_fixup(PoreInlineContext *ctx,
+ PoreInlineLocation source,
+ PoreInlineLocation target)
+{
+ uint32_t instruction;
+ int32_t distance;
+ uint64_t imm;
+ int opcode, reg;
+ PoreInlineContext source_ctx;
+
+ if ((source < ctx->original_lc) ||
+ (source > ctx->lc)) {
+ ctx->error = PORE_INLINE_ILLEGAL_SOURCE_LC;
+ } else {
+
+ // Create a context as it existed when the source instruction was
+ // initially assembled, and then reassemble the instruction in that
+ // context with the actual target.
+
+ distance = ctx->lc - source;
+
+ source_ctx = *ctx;
+ source_ctx.lc = source;
+ source_ctx.remaining += distance;
+ source_ctx.lc_address -= distance;
+ source_ctx.error = 0;
+
+ instruction = pore_inline_host32(source_ctx.lc_address);
+ opcode = (instruction >> 25);
+ reg = (instruction >> 20) & 0xf;
+
+ switch (opcode) {
+ case PGAS_OPCODE_BRA:
+ pore_BRA(&source_ctx, target);
+ break;
+ case PGAS_OPCODE_BSR:
+ pore_BSR(&source_ctx, target);
+ break;
+ case PGAS_OPCODE_LOOP:
+ pore_LOOP(&source_ctx, target);
+ break;
+ case PGAS_OPCODE_BRAZ:
+ pore_BRAZ(&source_ctx, reg, target);
+ break;
+ case PGAS_OPCODE_BRANZ:
+ pore_BRANZ(&source_ctx, reg, target);
+ break;
+ case PGAS_OPCODE_CMPIBRAEQ:
+ imm = pore_inline_host64(source_ctx.lc_address + 4);
+ pore_CMPIBRAEQ(&source_ctx, D0, target, imm);
+ break;
+ case PGAS_OPCODE_CMPIBRANE:
+ imm = pore_inline_host64(source_ctx.lc_address + 4);
+ pore_CMPIBRANE(&source_ctx, D0, target, imm);
+ break;
+ case PGAS_OPCODE_CMPIBSREQ:
+ imm = pore_inline_host64(source_ctx.lc_address + 4);
+ pore_CMPIBSREQ(&source_ctx, D0, target, imm);
+ break;
+ default:
+ source_ctx.error = PORE_INLINE_NOT_A_BRANCH;
+ break;
+ }
+
+ ctx->error = source_ctx.error;
+ }
+ return ctx->error;
+}
diff --git a/roms/skiboot/libpore/sbe_xip_image.c b/roms/skiboot/libpore/sbe_xip_image.c
new file mode 100644
index 000000000..2b05a0b90
--- /dev/null
+++ b/roms/skiboot/libpore/sbe_xip_image.c
@@ -0,0 +1,2572 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/hwpf/hwp/build_winkle_images/p8_slw_build/sbe_xip_image.c $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2012,2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+// $Id: sbe_xip_image.c,v 1.31 2015/07/29 23:40:06 cmolsen Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ipl/sbe/sbe_xip_image.c,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2011
+// *! All Rights Reserved -- Property of IBM
+// *! *** ***
+//-----------------------------------------------------------------------------
+// *! OWNER NAME: Bishop Brock Email: bcbrock@us.ibm.com
+//------------------------------------------------------------------------------
+
+/// \file sbe_xip_image.c
+/// \brief APIs for validating, normalizing, searching and manipulating
+/// SBE-XIP images.
+///
+/// The background, APIs and implementation details are documented in the
+/// document "SBE-XIP Binary format" currently available at this link:
+///
+/// - https://mcdoc.boeblingen.de.ibm.com/out/out.ViewDocument.php?documentid=2678
+///
+/// \bug The sbe_xip_validate() API should be carefully reviewed to ensure
+/// that validating even a corrupt image can not lead to a segfault, i.e., to
+/// ensure that no memory outside of the putative bounds of the image is ever
+/// referenced during validation.
+
+#ifndef PLIC_MODULE
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#endif // PLIC_MODULE
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "sbe_xip_image.h"
+
+
+////////////////////////////////////////////////////////////////////////////
+// Local Functions
+////////////////////////////////////////////////////////////////////////////
+
+// PHYP has their own way of implementing the <string.h> functions. PHYP also
+// does not allow static functions or data, so all of the XIP_STATIC functions
+// defined here are global to PHYP.
+
+#ifdef PPC_HYP
+
+#ifdef PLIC_MODULE
+
+#define strcpy(dest, src) hvstrcpy(dest, src)
+#define strlen(s) hvstrlen(s)
+#define strcmp(s1, s2) hvstrcmp(s1, s2)
+#endif //PLIC_MODULE
+
+#define XIP_STATIC
+
+#else // PPC_HYP
+
+#define XIP_STATIC static
+
+#endif // PPC_HYP
+
+
+#ifdef DEBUG_SBE_XIP_IMAGE
+
+// Debugging support, normally disabled. All of the formatted I/O you see in
+// the code is effectively under this switch.
+
+#ifdef __FAPI
+
+#include "fapi.H"
+#define fprintf(stream, ...) FAPI_ERR(__VA_ARGS__)
+#define printf(...) FAPI_INF(__VA_ARGS__)
+#define TRACE_NEWLINE ""
+
+#else // __FAPI
+
+#include <stdio.h>
+#define TRACE_NEWLINE "\n"
+
+#endif // __FAPI
+
+// Portable formatting of uint64_t. The ISO C99 standard requires
+// __STDC_FORMAT_MACROS to be defined in order for PRIx64 etc. to be defined.
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#define F0x016llx "0x%016" PRIx64
+#define F0x012llx "0x%012" PRIx64
+
+XIP_STATIC SBE_XIP_ERROR_STRINGS(sbe_xip_error_strings);
+
+#define TRACE_ERROR(x) \
+ ({ \
+ fprintf(stderr, "%s:%d : Returning error code %d : %s" TRACE_NEWLINE, \
+ __FILE__, __LINE__, (x), \
+ SBE_XIP_ERROR_STRING(sbe_xip_error_strings, (x))); \
+ (x); \
+ })
+
+#define TRACE_ERRORX(x, ...) \
+ ({ \
+ TRACE_ERROR(x); \
+ fprintf(stderr, ##__VA_ARGS__); \
+ (x); \
+ })
+
+
+// Uncomment these if required for debugging, otherwise we get warnings from
+// GCC as they are not otherwise used.
+
+#if 0
+
+XIP_STATIC uint32_t xipRevLe32(const uint32_t i_x);
+
+XIP_STATIC SBE_XIP_TYPE_STRINGS(type_strings);
+
+XIP_STATIC void
+dumpToc(int index, SbeXipToc* toc)
+{
+ printf("TOC entry %d @ %p\n"
+ " iv_id = 0x%08x\n"
+ " iv_data = 0x%08x\n"
+ " iv_type = %s\n"
+ " iv_section = 0x%02x\n"
+ " iv_elements = %d\n",
+ index, toc,
+ xipRevLe32(toc->iv_id),
+ xipRevLe32(toc->iv_data),
+ SBE_XIP_TYPE_STRING(type_strings, toc->iv_type),
+ toc->iv_section,
+ toc->iv_elements);
+}
+
+#endif
+
+#if 0
+
+XIP_STATIC void
+dumpItem(SbeXipItem* item)
+{
+ printf("SbeXipItem @ %p\n"
+ " iv_toc = %p\n"
+ " iv_address = " F0x016llx "\n"
+ " iv_imageData = %p\n"
+ " iv_id = %s\n"
+ " iv_type = %s\n"
+ " iv_elements = %d\n",
+ item,
+ item->iv_toc,
+ item->iv_address,
+ item->iv_imageData,
+ item->iv_id,
+ SBE_XIP_TYPE_STRING(type_strings, item->iv_type),
+ item->iv_elements);
+ dumpToc(-1, item->iv_toc);
+}
+
+#endif /* 0 */
+
+XIP_STATIC void
+dumpSectionTable(const void* i_image)
+{
+ int i, rc;
+ SbeXipSection section;
+
+ printf("Section table dump of image @ %p\n"
+ " Entry Offset Size\n"
+ "-------------------------------\n",
+ i_image);
+
+ for (i = 0; i < SBE_XIP_SECTIONS; i++) {
+ rc = sbe_xip_get_section(i_image, i, &section);
+ if (rc) {
+ printf(">>> dumpSectionTable got error at entry %d : %s\n",
+ i, SBE_XIP_ERROR_STRING(sbe_xip_error_strings, rc));
+ break;
+ }
+ printf("%7d 0x%08x 0x%08x\n",
+ i, section.iv_offset, section.iv_size);
+ }
+}
+
+#else
+
+#define TRACE_ERROR(x) (x)
+#define TRACE_ERRORX(x, ...) (x)
+#define dumpToc(...)
+#define dumpItem(...)
+#define dumpSectionTable(...)
+
+#endif
+
+
+// Note: For maximum flexibility we provide private versions of
+// endian-conversion routines rather than counting on a system-specific header
+// to provide these.
+
+/// Byte-reverse a 16-bit integer if on a little-endian machine
+
+XIP_STATIC uint16_t
+xipRevLe16(const uint16_t i_x)
+{
+ uint16_t rx;
+
+#ifndef _BIG_ENDIAN
+ uint8_t *pix = (uint8_t*)(&i_x);
+ uint8_t *prx = (uint8_t*)(&rx);
+
+ prx[0] = pix[1];
+ prx[1] = pix[0];
+#else
+ rx = i_x;
+#endif
+
+ return rx;
+}
+
+
+/// Byte-reverse a 32-bit integer if on a little-endian machine
+
+XIP_STATIC uint32_t
+xipRevLe32(const uint32_t i_x)
+{
+ uint32_t rx;
+
+#ifndef _BIG_ENDIAN
+ uint8_t *pix = (uint8_t*)(&i_x);
+ uint8_t *prx = (uint8_t*)(&rx);
+
+ prx[0] = pix[3];
+ prx[1] = pix[2];
+ prx[2] = pix[1];
+ prx[3] = pix[0];
+#else
+ rx = i_x;
+#endif
+
+ return rx;
+}
+
+
+/// Byte-reverse a 64-bit integer if on a little-endian machine
+
+XIP_STATIC uint64_t
+xipRevLe64(const uint64_t i_x)
+{
+ uint64_t rx;
+
+#ifndef _BIG_ENDIAN
+ uint8_t *pix = (uint8_t*)(&i_x);
+ uint8_t *prx = (uint8_t*)(&rx);
+
+ prx[0] = pix[7];
+ prx[1] = pix[6];
+ prx[2] = pix[5];
+ prx[3] = pix[4];
+ prx[4] = pix[3];
+ prx[5] = pix[2];
+ prx[6] = pix[1];
+ prx[7] = pix[0];
+#else
+ rx = i_x;
+#endif
+
+ return rx;
+}
+
+
+/// What is the image link address?
+
+XIP_STATIC uint64_t
+xipLinkAddress(const void* i_image)
+{
+ return xipRevLe64(((SbeXipHeader*)i_image)->iv_linkAddress);
+}
+
+
+/// What is the image size?
+
+XIP_STATIC uint32_t
+xipImageSize(const void* i_image)
+{
+ return xipRevLe32(((SbeXipHeader*)i_image)->iv_imageSize);
+}
+
+
+/// Set the image size
+
+XIP_STATIC void
+xipSetImageSize(void* io_image, const size_t i_size)
+{
+ ((SbeXipHeader*)io_image)->iv_imageSize = xipRevLe32(i_size);
+}
+
+
+/// Re-establish the required final alignment
+
+XIP_STATIC void
+xipFinalAlignment(void* io_image)
+{
+ uint32_t size;
+
+ size = xipImageSize(io_image);
+
+ if ((size % SBE_XIP_FINAL_ALIGNMENT) != 0) {
+ xipSetImageSize(io_image,
+ size + (SBE_XIP_FINAL_ALIGNMENT -
+ (size % SBE_XIP_FINAL_ALIGNMENT)));
+ }
+}
+
+
+/// Compute a host address from an image address and offset
+
+XIP_STATIC void*
+xipHostAddressFromOffset(const void* i_image, const uint32_t offset)
+{
+ return (void*)((unsigned long)i_image + offset);
+}
+
+
+/// Convert a PORE address to a host address
+
+XIP_STATIC void*
+xipPore2Host(const void* i_image, const uint64_t i_poreAddress)
+{
+ return xipHostAddressFromOffset(i_image,
+ i_poreAddress - xipLinkAddress(i_image));
+}
+
+
+XIP_STATIC int
+xipValidatePoreAddress(const void* i_image,
+ const uint64_t i_poreAddress,
+ const uint32_t size)
+{
+ int rc;
+
+ if ((i_poreAddress < xipLinkAddress(i_image)) ||
+ (i_poreAddress > (xipLinkAddress(i_image) +
+ xipImageSize(i_image) -
+ size))) {
+ rc = TRACE_ERRORX(SBE_XIP_INVALID_ARGUMENT,
+ "The PORE address " F0x012llx
+ " is outside the bounds "
+ "of the image ("
+ F0x012llx ":" F0x012llx
+ ") for %u-byte access.\n",
+ i_poreAddress,
+ xipLinkAddress(i_image),
+ xipLinkAddress(i_image) + xipImageSize(i_image) - 1,
+ size);
+ } else {
+ rc = 0;
+ }
+ return rc;
+}
+
+
+/// Get the magic number from the image
+
+XIP_STATIC uint64_t
+xipMagic(const void* i_image)
+{
+ return xipRevLe64(((SbeXipHeader*)i_image)->iv_magic);
+}
+
+
+/// Get the header version from the image
+
+XIP_STATIC uint8_t
+xipHeaderVersion(const void* i_image)
+{
+ return ((SbeXipHeader*)i_image)->iv_headerVersion;
+}
+
+
+/// Has the image been normalized?
+
+XIP_STATIC uint8_t
+xipNormalized(const void* i_image)
+{
+ return ((SbeXipHeader*)i_image)->iv_normalized;
+}
+
+
+/// Has the image TOC been sorted?
+
+XIP_STATIC uint8_t
+xipSorted(const void* i_image)
+{
+ return ((SbeXipHeader*)i_image)->iv_tocSorted;
+}
+
+
+/// A quick check that the image exists, has the correct magic and header
+/// version, and optionally is normalized.
+
+XIP_STATIC int
+xipQuickCheck(const void* i_image, const int i_normalizationRequired)
+{
+ int rc;
+
+ do {
+ rc = 0;
+
+ if (i_image == 0) {
+ rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
+ "Image pointer is NULL (0)\n");
+ break;
+ }
+ if ((xipMagic(i_image) >> 32) != SBE_XIP_MAGIC) {
+ rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
+ "Magic number mismatch; Found "
+ "" F0x016llx ", expected 0x%08x........\n",
+ xipMagic(i_image), SBE_XIP_MAGIC);
+ break;
+ }
+ if ((xipHeaderVersion(i_image)) != SBE_XIP_HEADER_VERSION) {
+ rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
+ "Header version mismatch; Expecting %d, "
+ "found %d\n",
+ SBE_XIP_HEADER_VERSION,
+ xipHeaderVersion(i_image));
+ break;
+ }
+ if (i_normalizationRequired && !xipNormalized(i_image)) {
+ rc = TRACE_ERRORX(SBE_XIP_NOT_NORMALIZED,
+ "Image not normalized\n");
+ break;
+ }
+ } while(0);
+
+ return rc;
+}
+
+
+/// Convert a 32-bit relocatable offset to a full PORE 48-bit address
+
+XIP_STATIC uint64_t
+xipFullAddress(const void* i_image, uint32_t offset)
+{
+ return (xipLinkAddress(i_image) & 0x0000ffff00000000ull) + offset;
+}
+
+
+/// Translate a section table entry
+
+XIP_STATIC void
+xipTranslateSection(SbeXipSection* o_dest, const SbeXipSection* i_src)
+{
+#ifndef _BIG_ENDIAN
+
+#if SBE_XIP_HEADER_VERSION != 8
+#error This code assumes the SBE-XIP header version 8 layout
+#endif
+
+ o_dest->iv_offset = xipRevLe32(i_src->iv_offset);
+ o_dest->iv_size = xipRevLe32(i_src->iv_size);
+ o_dest->iv_alignment = i_src->iv_alignment;
+ o_dest->iv_reserved8[0] = 0;
+ o_dest->iv_reserved8[1] = 0;
+ o_dest->iv_reserved8[2] = 0;
+#else
+ if (o_dest != i_src) {
+ *o_dest = *i_src;
+ }
+#endif /* _BIG_ENDIAN */
+}
+
+
+/// Translate a TOC entry
+
+XIP_STATIC void
+xipTranslateToc(SbeXipToc* o_dest, SbeXipToc* i_src)
+{
+#ifndef _BIG_ENDIAN
+
+#if SBE_XIP_HEADER_VERSION != 8
+#error This code assumes the SBE-XIP header version 8 layout
+#endif
+
+ o_dest->iv_id = xipRevLe32(i_src->iv_id);
+ o_dest->iv_data = xipRevLe32(i_src->iv_data);
+ o_dest->iv_type = i_src->iv_type;
+ o_dest->iv_section = i_src->iv_section;
+ o_dest->iv_elements = i_src->iv_elements;
+ o_dest->iv_pad = 0;
+#else
+ if (o_dest != i_src) {
+ *o_dest = *i_src;
+ }
+#endif /* _BIG_ENDIAN */
+}
+
+
+/// Find the final (highest-address) section of the image
+
+XIP_STATIC int
+xipFinalSection(const void* i_image, int* o_sectionId)
+{
+ int i, rc, found;
+ uint32_t offset;
+ SbeXipHeader hostHeader;
+
+ sbe_xip_translate_header(&hostHeader, (SbeXipHeader*)i_image);
+
+ found = 0;
+ offset = 0;
+ *o_sectionId = 0; /* Make GCC -O3 happy */
+ for (i = 0; i < SBE_XIP_SECTIONS; i++) {
+ if ((hostHeader.iv_section[i].iv_size != 0) &&
+ (hostHeader.iv_section[i].iv_offset >= offset)) {
+ *o_sectionId = i;
+ offset = hostHeader.iv_section[i].iv_offset;
+ found = 1;
+ }
+ }
+ if (!found) {
+ rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR, "The image is empty\n");
+ } else {
+ rc = 0;
+ }
+ return rc;
+}
+
+
+/// Return a pointer to an image-format section table entry
+
+XIP_STATIC int
+xipGetSectionPointer(const void* i_image,
+ const int i_sectionId,
+ SbeXipSection** o_imageSection)
+{
+ int rc;
+
+ if ((i_sectionId < 0) || (i_sectionId >= SBE_XIP_SECTIONS)) {
+ rc = TRACE_ERROR(SBE_XIP_INVALID_ARGUMENT);
+ } else {
+ *o_imageSection =
+ &(((SbeXipHeader*)i_image)->iv_section[i_sectionId]);
+ rc = 0;
+ }
+ return rc;
+}
+
+
+/// Restore a section table entry from host format to image format.
+
+XIP_STATIC int
+xipPutSection(const void* i_image,
+ const int i_sectionId,
+ SbeXipSection* i_hostSection)
+{
+ int rc;
+ SbeXipSection *imageSection = NULL;
+
+ rc = xipGetSectionPointer(i_image, i_sectionId, &imageSection);
+
+ if (!rc) {
+ xipTranslateSection(imageSection, i_hostSection);
+ }
+
+ return rc;
+}
+
+
+/// Set the offset of a section
+
+XIP_STATIC int
+xipSetSectionOffset(void* io_image, const int i_section,
+ const uint32_t i_offset)
+{
+ SbeXipSection* section = NULL;
+ int rc;
+
+ rc = xipGetSectionPointer(io_image, i_section, &section);
+ if (!rc) {
+ section->iv_offset = xipRevLe32(i_offset);
+ }
+ return rc;
+}
+
+
+/// Set the size of a section
+
+XIP_STATIC int
+xipSetSectionSize(void* io_image, const int i_section, const uint32_t i_size)
+{
+ SbeXipSection* section = NULL;
+ int rc;
+
+ rc = xipGetSectionPointer(io_image, i_section, &section);
+ if (!rc) {
+ section->iv_size = xipRevLe32(i_size);
+ }
+ return rc;
+}
+
+
+/// Translate a PORE address in the image to a section and offset
+
+// We first check to be sure that the PORE address is contained in the image,
+// using the full 48-bit form. Then we scan the section table to see which
+// section contains the address - if none then the image is corrupted. We can
+// (must) use the 32-bit offset form of the address here.
+
+XIP_STATIC int
+xipPore2Section(const void* i_image,
+ const uint64_t i_poreAddress,
+ int* o_section,
+ uint32_t* o_offset)
+{
+ int rc, sectionId;
+ SbeXipSection section;
+ uint32_t addressOffset;
+
+ do {
+ rc = 0;
+
+ if ((i_poreAddress < xipLinkAddress(i_image)) ||
+ (i_poreAddress >
+ (xipLinkAddress(i_image) + xipImageSize(i_image)))) {
+ rc = TRACE_ERRORX(SBE_XIP_INVALID_ARGUMENT,
+ "pore2section: The i_poreAddress argument "
+ "(" F0x016llx ")\nis outside the bounds of the "
+ "image (" F0x016llx ":" F0x016llx ")\n",
+ i_poreAddress,
+ xipLinkAddress(i_image),
+ xipLinkAddress(i_image) + xipImageSize(i_image));
+ break;
+ }
+
+ addressOffset = (i_poreAddress - xipLinkAddress(i_image)) & 0xffffffff;
+
+ for (sectionId = 0; sectionId < SBE_XIP_SECTIONS; sectionId++) {
+ rc = sbe_xip_get_section(i_image, sectionId, &section);
+ if (rc) {
+ rc = TRACE_ERROR(SBE_XIP_BUG); /* Can't happen */
+ break;
+ }
+ if ((section.iv_size != 0) &&
+ (addressOffset >= section.iv_offset) &&
+ (addressOffset < (section.iv_offset + section.iv_size))) {
+ break;
+ }
+ }
+ if (rc) break;
+
+ if (sectionId == SBE_XIP_SECTIONS) {
+ rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
+ "Error processing PORE address " F0x016llx ". "
+ "The address is not mapped in any section.\n"
+ "A section table dump appears below\n",
+ i_poreAddress);
+ dumpSectionTable(i_image);
+ break;
+ }
+
+ *o_section = sectionId;
+ *o_offset = addressOffset - section.iv_offset;
+
+ } while(0);
+
+ return rc;
+}
+
+
+/// Get the information required to search the TOC.
+///
+/// All return values are optional.
+
+XIP_STATIC int
+xipGetToc(void* i_image,
+ SbeXipToc** o_toc,
+ size_t* o_entries,
+ int* o_sorted,
+ char** o_strings)
+{
+ int rc;
+ SbeXipSection tocSection, stringsSection;
+
+ do {
+ rc = sbe_xip_get_section(i_image, SBE_XIP_SECTION_TOC, &tocSection);
+ if (rc) break;
+
+ rc = sbe_xip_get_section(i_image, SBE_XIP_SECTION_STRINGS,
+ &stringsSection);
+ if (rc) break;
+
+ if (o_toc) {
+ *o_toc = (SbeXipToc*)((uint8_t*)i_image + tocSection.iv_offset);
+ }
+ if (o_entries) {
+ *o_entries = tocSection.iv_size / sizeof(SbeXipToc);
+ }
+ if (o_sorted) {
+ *o_sorted = xipSorted(i_image);
+ }
+ if (o_strings) {
+ *o_strings = (char*)i_image + stringsSection.iv_offset;
+ }
+ } while (0);
+ return rc;
+}
+
+
+/// Compare two normalized TOC entries for sorting.
+
+XIP_STATIC int
+xipCompareToc(const SbeXipToc* i_a, const SbeXipToc* i_b,
+ const char* i_strings)
+{
+ return strcmp(i_strings + xipRevLe32(i_a->iv_id),
+ i_strings + xipRevLe32(i_b->iv_id));
+}
+
+
+/// Iterative quicksort of the TOC
+
+// Note: The stack requirement is limited to 256 bytes + minor local storage.
+
+XIP_STATIC void
+xipQuickSort(SbeXipToc* io_toc, int i_left, int i_right,
+ const char* i_strings)
+{
+ int i, j, left, right, sp;
+ SbeXipToc pivot, temp;
+ uint32_t stack[64];
+
+ sp = 0;
+ stack[sp++] = i_left;
+ stack[sp++] = i_right;
+
+ while (sp) {
+
+ right = stack[--sp];
+ left = stack[--sp];
+
+ i = left;
+ j = right;
+
+ pivot = io_toc[(i + j) / 2];
+
+ while (i <= j) {
+ while (xipCompareToc(&(io_toc[i]), &pivot, i_strings) < 0) {
+ i++;
+ }
+ while (xipCompareToc(&(io_toc[j]), &pivot, i_strings) > 0) {
+ j--;
+ }
+ if (i <= j) {
+ temp = io_toc[i];
+ io_toc[i] = io_toc[j];
+ io_toc[j] = temp;
+ i++;
+ j--;
+ }
+ }
+ if (left < j) {
+ stack[sp++] = left;
+ stack[sp++] = j;
+ }
+ if (i < right) {
+ stack[sp++] = i;
+ stack[sp++] = right;
+ }
+ }
+}
+
+
+/// TOC linear search
+
+XIP_STATIC int
+xipLinearSearch(void* i_image, const char* i_id, SbeXipToc** o_entry)
+{
+ int rc;
+ SbeXipToc *imageToc, hostToc;
+ size_t entries;
+ char* strings;
+
+ *o_entry = 0;
+ rc = xipGetToc(i_image, &imageToc, &entries, 0, &strings);
+ if (!rc) {
+ for (; entries; entries--, imageToc++) {
+ xipTranslateToc(&hostToc, imageToc);
+ if (strcmp(i_id, strings + hostToc.iv_id) == 0) {
+ break;
+ }
+ }
+ if (entries) {
+ *o_entry = imageToc;
+ rc = 0;
+ } else {
+ *o_entry = 0;
+ rc = TRACE_ERROR(SBE_XIP_ITEM_NOT_FOUND);
+ }
+ }
+ return rc;
+}
+
+
+/// A classic binary search of a (presumed) sorted array
+
+XIP_STATIC int
+xipBinarySearch(void* i_image, const char* i_id, SbeXipToc** o_entry)
+{
+ int rc;
+ SbeXipToc *imageToc;
+ size_t entries;
+ char* strings;
+ int sorted, left, right, next, sort;
+
+ do {
+ *o_entry = 0;
+
+ rc = xipGetToc(i_image, &imageToc, &entries, &sorted, &strings);
+ if (rc) break;
+
+ if (!sorted) {
+ rc = TRACE_ERROR(SBE_XIP_BUG);
+ break;
+ }
+
+ left = 0;
+ right = entries - 1;
+ while (left <= right) {
+ next = (left + right) / 2;
+ sort = strcmp(i_id, strings + xipRevLe32(imageToc[next].iv_id));
+ if (sort == 0) {
+ *o_entry = &(imageToc[next]);
+ break;
+ } else if (sort < 0) {
+ right = next - 1;
+ } else {
+ left = next + 1;
+ }
+ }
+ if (*o_entry == 0) {
+ rc = TRACE_ERROR(SBE_XIP_ITEM_NOT_FOUND);
+ break;
+ }
+ } while (0);
+ return rc;
+}
+
+
+/// Validate a TOC entry as a mapping function
+///
+/// The TOC is validated by searching for the entry, which will uncover
+/// duplicate entries or problems with sorting/searching.
+
+XIP_STATIC int
+xipValidateTocEntry(void* io_image, const SbeXipItem* i_item, void* io_arg)
+{
+ int rc;
+ SbeXipItem found;
+
+ (void)io_arg;
+
+ do {
+ rc = sbe_xip_find(io_image, i_item->iv_id, &found);
+ if (rc) {
+ rc = TRACE_ERRORX(rc, "TOC entry for %s not found\n",
+ i_item->iv_id);
+ } else if (found.iv_toc != i_item->iv_toc) {
+ rc = TRACE_ERRORX(SBE_XIP_TOC_ERROR,
+ "Duplicate TOC entry for '%s'\n", i_item->iv_id);
+ }
+ break;
+ } while (0);
+ return rc;
+}
+
+
+// This is the FNV-1a hash, used for hashing symbol names in the .fixed
+// section into 32-bit hashes for the mini-TOC.
+
+// According to the authors:
+
+// "FNV hash algorithms and source code have been released into the public
+// domain. The authors of the FNV algorithmm look deliberate steps to disclose
+// the algorhtm (sic) in a public forum soon after it was invented. More than
+// a year passed after this public disclosure and the authors deliberately took
+// no steps to patent the FNV algorithm. Therefore it is safe to say that the
+// FNV authors have no patent claims on the FNV algorithm as published."
+
+#define FNV_OFFSET_BASIS 2166136261u
+#define FNV_PRIME32 16777619u
+
+static uint32_t
+xipHash32(const char* s)
+{
+ uint32_t hash;
+
+ hash = FNV_OFFSET_BASIS;
+ while (*s) {
+ hash ^= *s++;
+ hash *= FNV_PRIME32;
+ }
+ return hash;
+}
+
+
+// Normalize a TOC entry
+
+// Normalize the TOC entry by converting relocatable pointers into 32-bit
+// offsets from the beginning of the section containing the data. All
+// addresses in the TOC are actually 32-bit offsets in the address space named
+// in bits 16:31 of the link address of the image.
+
+XIP_STATIC int
+xipNormalizeToc(void* io_image, SbeXipToc *io_imageToc,
+ SbeXipHashedToc** io_fixedTocEntry,
+ size_t* io_fixedEntriesRemaining)
+{
+ SbeXipToc hostToc;
+ int idSection, dataSection;
+ uint32_t idOffset, dataOffset;
+ char* hostString;
+ int rc;
+
+ do {
+
+ // Translate the TOC entry to host format. Then locate the
+ // sections/offsets of the Id string (which must be in .strings) and
+ // the data.
+
+ xipTranslateToc(&hostToc, io_imageToc);
+
+ hostString =
+ (char*)xipPore2Host(io_image,
+ xipFullAddress(io_image, hostToc.iv_id));
+
+ rc = xipPore2Section(io_image,
+ xipFullAddress(io_image, hostToc.iv_id),
+ &idSection,
+ &idOffset);
+ if (rc) break;
+
+ if (idSection != SBE_XIP_SECTION_STRINGS) {
+ rc = TRACE_ERROR(SBE_XIP_IMAGE_ERROR);
+ break;
+ }
+
+ rc = xipPore2Section(io_image,
+ xipFullAddress(io_image, hostToc.iv_data),
+ &dataSection,
+ &dataOffset);
+ if (rc) break;
+
+ // Now replace the Id and data pointers with their offsets, and update
+ // the data section in the TOC entry.
+
+ hostToc.iv_id = idOffset;
+ hostToc.iv_data = dataOffset;
+ hostToc.iv_section = dataSection;
+
+ // If this TOC entry is from .fixed, create a new record in .fixed_toc
+
+ if (hostToc.iv_section == SBE_XIP_SECTION_FIXED) {
+
+ if (*io_fixedEntriesRemaining == 0) {
+ rc = TRACE_ERRORX(SBE_XIP_TOC_ERROR,
+ "Too many TOC entries for .fixed\n");
+ break;
+ }
+ if (hostToc.iv_data != (uint16_t)hostToc.iv_data) {
+ rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
+ "The .fixed section is too big to index\n");
+ break;
+ }
+
+ (*io_fixedTocEntry)->iv_hash = xipRevLe32(xipHash32(hostString));
+ (*io_fixedTocEntry)->iv_offset = xipRevLe16(hostToc.iv_data);
+ (*io_fixedTocEntry)->iv_type = hostToc.iv_type;
+ (*io_fixedTocEntry)->iv_elements = hostToc.iv_elements;
+
+ (*io_fixedTocEntry)++;
+ (*io_fixedEntriesRemaining)--;
+ }
+
+ // Finally update the TOC entry
+
+ xipTranslateToc(io_imageToc, &hostToc);
+
+ } while (0);
+
+ return rc;
+}
+
+
+// Check for hash collisions in the .fixed mini-TOC. Note that endianness is
+// not an issue here, as we're comparing for equality.
+
+XIP_STATIC int
+xipHashCollision(SbeXipHashedToc* i_fixedToc, size_t i_entries)
+{
+ int rc;
+ size_t i, j;
+
+ rc = 0;
+
+ for (i = 0; i < i_entries; i++) {
+ for (j = i + 1; j < i_entries; j++) {
+ if (i_fixedToc[i].iv_hash == i_fixedToc[j].iv_hash) {
+ rc = TRACE_ERRORX(SBE_XIP_HASH_COLLISION,
+ "Hash collision at index %d\n",
+ i);
+ break;
+ }
+ }
+ if (rc) break;
+ }
+
+ return rc;
+}
+
+
+/// Decode a normalized image-format TOC entry into a host-format SbeXipItem
+/// structure
+
+XIP_STATIC int
+xipDecodeToc(void* i_image,
+ SbeXipToc* i_imageToc,
+ SbeXipItem* o_item)
+{
+ int rc;
+ SbeXipToc hostToc;
+ SbeXipSection dataSection, stringsSection;
+
+ do {
+ if (!xipNormalized(i_image)) {
+ rc = TRACE_ERROR(SBE_XIP_NOT_NORMALIZED);
+ break;
+ }
+
+
+ // Translate the TOC entry and set the TOC pointer, data type and
+ // number of elements in the outgoing structure. The Id string is
+ // always located in the TOC_STRINGS section.
+
+ xipTranslateToc(&hostToc, i_imageToc);
+
+ o_item->iv_toc = i_imageToc;
+ o_item->iv_type = hostToc.iv_type;
+ o_item->iv_elements = hostToc.iv_elements;
+
+ rc = sbe_xip_get_section(i_image, SBE_XIP_SECTION_STRINGS,
+ &stringsSection);
+ if (rc) break;
+
+ o_item->iv_id =
+ (char*)i_image + stringsSection.iv_offset + hostToc.iv_id;
+
+
+ // The data (or text address) are addressed by relative offsets from
+ // the beginning of their section. The TOC entry may remain in the TOC
+ // even though the section has been removed from the image, so this
+ // case needs to be covered.
+
+ rc = sbe_xip_get_section(i_image, hostToc.iv_section, &dataSection);
+ if (rc) break;
+
+ if (dataSection.iv_size == 0) {
+ rc = TRACE_ERROR(SBE_XIP_DATA_NOT_PRESENT);
+ break;
+ }
+
+ o_item->iv_imageData =
+ (void*)((uint8_t*)i_image +
+ dataSection.iv_offset + hostToc.iv_data);
+
+ o_item->iv_address =
+ xipLinkAddress(i_image) + dataSection.iv_offset + hostToc.iv_data;
+
+ o_item->iv_partial = 0;
+
+ } while (0);
+ return rc;
+}
+
+
+/// Sort the TOC
+
+XIP_STATIC int
+xipSortToc(void* io_image)
+{
+ int rc;
+ SbeXipToc *hostToc;
+ size_t entries;
+ char* strings;
+
+ do {
+ rc = xipQuickCheck(io_image, 1);
+ if (rc) break;
+
+ if (xipSorted(io_image)) break;
+
+ rc = xipGetToc(io_image, &hostToc, &entries, 0, &strings);
+ if (rc) break;
+
+ xipQuickSort(hostToc, 0, entries - 1, strings);
+
+ ((SbeXipHeader*)io_image)->iv_tocSorted = 1;
+
+ } while (0);
+
+ return rc;
+}
+
+
+// Pad the image with 0 to a given power-of-2 alignment. The image size is
+// modified to reflect the pad, but the caller must modify the section size to
+// reflect the pad.
+
+XIP_STATIC int
+xipPadImage(void* io_image, uint32_t i_allocation,
+ uint32_t i_align, uint32_t* pad)
+{
+ int rc;
+
+ do {
+ rc = 0;
+
+ if ((i_align == 0) || ((i_align & (i_align - 1)) != 0)) {
+ rc = TRACE_ERRORX(SBE_XIP_INVALID_ARGUMENT,
+ "Alignment specification (%u) "
+ "not a power-of-2\n",
+ i_align);
+ break;
+ }
+
+ *pad = xipImageSize(io_image) % i_align;
+ if (*pad != 0) {
+ *pad = i_align - *pad;
+
+ if ((xipImageSize(io_image) + *pad) > i_allocation) {
+ rc = TRACE_ERROR(SBE_XIP_WOULD_OVERFLOW);
+ break;
+ }
+
+ memset((void*)((unsigned long)io_image + xipImageSize(io_image)),
+ 0, *pad);
+ xipSetImageSize(io_image, xipImageSize(io_image) + *pad);
+ }
+ } while (0);
+
+ return rc;
+}
+
+
+// Get the .fixed_toc section
+
+XIP_STATIC int
+xipGetFixedToc(void* io_image,
+ SbeXipHashedToc** o_imageToc,
+ size_t* o_entries)
+{
+ int rc;
+ SbeXipSection section;
+
+ rc = sbe_xip_get_section(io_image, SBE_XIP_SECTION_FIXED_TOC, &section);
+ if (!rc) {
+
+ *o_imageToc =
+ (SbeXipHashedToc*)((unsigned long)io_image + section.iv_offset);
+
+ *o_entries = section.iv_size / sizeof(SbeXipHashedToc);
+ }
+
+ return rc;
+}
+
+
+// Search for an item in the fixed TOC, and populate a partial TOC entry if
+// requested. This table is small and unsorted so a linear search is
+// adequate. The TOC structures are also small so all byte-reversal is done
+// 'by hand' rather than with a translate-type API.
+
+XIP_STATIC int
+xipFixedFind(void* i_image, const char* i_id, SbeXipItem* o_item)
+{
+ int rc;
+ SbeXipHashedToc* toc;
+ size_t entries;
+ uint32_t hash;
+ SbeXipSection fixedSection;
+ uint32_t offset;
+
+ do {
+ rc = xipGetFixedToc(i_image, &toc, &entries);
+ if (rc) break;
+
+ for (hash = xipRevLe32(xipHash32(i_id)); entries != 0; entries--, toc++) {
+ if (toc->iv_hash == hash) break;
+ }
+
+ if (entries == 0) {
+ rc = SBE_XIP_ITEM_NOT_FOUND;
+ break;
+ } else {
+ rc = 0;
+ }
+
+ // The caller may have requested a lookup only (o_item == 0), in which
+ // case we're done. Otherwise we create a partial SbeXipItem and
+ // populate the non-0 fields analogously to the xipDecodeToc()
+ // routine. The data resides in the .fixed section in this case.
+
+ if (o_item == 0) break;
+
+ o_item->iv_partial = 1;
+ o_item->iv_toc = 0;
+ o_item->iv_id = 0;
+
+ o_item->iv_type = toc->iv_type;
+ o_item->iv_elements = toc->iv_elements;
+
+ rc = sbe_xip_get_section(i_image, SBE_XIP_SECTION_FIXED, &fixedSection);
+ if (rc) break;
+
+ if (fixedSection.iv_size == 0) {
+ rc = TRACE_ERROR(SBE_XIP_DATA_NOT_PRESENT);
+ break;
+ }
+
+ offset = fixedSection.iv_offset + xipRevLe16(toc->iv_offset);
+
+ o_item->iv_imageData = (void*)((uint8_t*)i_image + offset);
+ o_item->iv_address = xipLinkAddress(i_image) + offset;
+
+ } while (0);
+
+ return rc;
+}
+
+
+// Search for an item in the special built-in TOC of header fields, and
+// populate a partial TOC entry if requested.
+//
+// This facility was added to allow header data to be searched by name even
+// when the TOC has been stripped. This API will only be used in the case of a
+// stripped TOC since the header fields are also indexed in the main TOC.
+//
+// The table is allocated on the stack in order to make this code concurrently
+// patchable in PHYP (although PHYP applications will never use this code).
+// The table is small and unsorted so a linear search is adequate, and the
+// stack requirememts are small.
+
+XIP_STATIC int
+xipHeaderFind(void* i_image, const char* i_id, SbeXipItem* o_item)
+{
+ int rc;
+ unsigned i;
+ uint32_t offset;
+ SbeXipSection headerSection;
+
+#define HEADER_TOC(id, field, type) \
+ {#id, offsetof(SbeXipHeader, field), type}
+
+ struct HeaderToc {
+
+ const char* iv_id;
+ uint16_t iv_offset;
+ uint8_t iv_type;
+
+ } toc[] = {
+
+ HEADER_TOC(magic, iv_magic, SBE_XIP_UINT64),
+ HEADER_TOC(entry_offset, iv_entryOffset, SBE_XIP_UINT64),
+ HEADER_TOC(link_address, iv_linkAddress, SBE_XIP_UINT64),
+
+ HEADER_TOC(image_size, iv_imageSize, SBE_XIP_UINT32),
+ HEADER_TOC(build_date, iv_buildDate, SBE_XIP_UINT32),
+ HEADER_TOC(build_time, iv_buildTime, SBE_XIP_UINT32),
+
+ HEADER_TOC(header_version, iv_headerVersion, SBE_XIP_UINT8),
+ HEADER_TOC(toc_normalized, iv_normalized, SBE_XIP_UINT8),
+ HEADER_TOC(toc_sorted, iv_tocSorted, SBE_XIP_UINT8),
+
+ HEADER_TOC(build_user, iv_buildUser, SBE_XIP_STRING),
+ HEADER_TOC(build_host, iv_buildHost, SBE_XIP_STRING),
+
+ };
+
+ do {
+
+ rc = SBE_XIP_ITEM_NOT_FOUND;
+ for (i = 0; i < (sizeof(toc) / sizeof(struct HeaderToc)); i++) {
+ if (strcmp(i_id, toc[i].iv_id) == 0) {
+ rc = 0;
+ break;
+ }
+ }
+
+ if (rc) break;
+
+ // The caller may have requested a lookup only (o_item == 0), in which
+ // case we're done. Otherwise we create a partial SbeXipItem and
+ // populate the non-0 fields analogously to the xipDecodeToc()
+ // routine. The data resides in the .fixed section in this case.
+
+ if (o_item == 0) break;
+
+ o_item->iv_partial = 1;
+ o_item->iv_toc = 0;
+ o_item->iv_id = 0;
+
+ o_item->iv_type = toc[i].iv_type;
+ o_item->iv_elements = 1; /* True for now... */
+
+ rc = sbe_xip_get_section(i_image, SBE_XIP_SECTION_HEADER,
+ &headerSection);
+ if (rc) break;
+
+ if (headerSection.iv_size == 0) {
+ rc = TRACE_ERROR(SBE_XIP_DATA_NOT_PRESENT);
+ break;
+ }
+
+ offset = headerSection.iv_offset + toc[i].iv_offset;
+
+ o_item->iv_imageData = (void*)((uint8_t*)i_image + offset);
+ o_item->iv_address = xipLinkAddress(i_image) + offset;
+
+ } while (0);
+
+ return rc;
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+// Published API
+////////////////////////////////////////////////////////////////////////////
+
+int
+sbe_xip_validate(void* i_image, const uint32_t i_size)
+{
+ SbeXipHeader hostHeader;
+ int rc = 0, i;
+ uint32_t linkAddress, imageSize, extent, offset, size;
+ uint8_t alignment;
+
+ sbe_xip_translate_header(&hostHeader, (SbeXipHeader*)i_image);
+
+ do {
+
+ // Validate C/Assembler constraints.
+
+ if (sizeof(SbeXipSection) != SIZE_OF_SBE_XIP_SECTION) {
+ rc = TRACE_ERRORX(SBE_XIP_BUG,
+ "C/Assembler size mismatch(%d/%d) "
+ "for SbeXipSection\n",
+ sizeof(SbeXipSection), SIZE_OF_SBE_XIP_SECTION);
+ break;
+ }
+
+ if (sizeof(SbeXipToc) != SIZE_OF_SBE_XIP_TOC) {
+ rc = TRACE_ERRORX(SBE_XIP_BUG,
+ "C/Assembler size mismatch(%d/%d) "
+ "for SbeXipToc\n",
+ sizeof(SbeXipToc), SIZE_OF_SBE_XIP_TOC);
+ break;
+ }
+
+ if (sizeof(SbeXipHashedToc) != SIZE_OF_SBE_XIP_HASHED_TOC) {
+ rc = TRACE_ERRORX(SBE_XIP_BUG,
+ "C/Assembler size mismatch(%d/%d) "
+ "for SbeXipHashedToc\n",
+ sizeof(SbeXipHashedToc),
+ SIZE_OF_SBE_XIP_HASHED_TOC);
+ break;
+ }
+
+ // Validate the image pointer and magic number
+
+ rc = xipQuickCheck(i_image, 0);
+ if (rc) break;
+
+ // Validate the image size
+
+ linkAddress = hostHeader.iv_linkAddress;
+ imageSize = hostHeader.iv_imageSize;
+ extent = linkAddress + imageSize;
+
+ if (imageSize < sizeof(SbeXipHeader)) {
+ rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
+ "sbe_xip_validate(%p, %u) : "
+ "The image size recorded in the image "
+ "(%u) is smaller than the header size.\n",
+ i_image, i_size, imageSize);
+ break;
+ }
+ if (imageSize != i_size) {
+ rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
+ "sbe_xip_validate(%p, %u) : "
+ "The image size recorded in the image "
+ "(%u) does not match the i_size parameter.\n",
+ i_image, i_size, imageSize);
+ break;
+ }
+ if (extent <= linkAddress) {
+ rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
+ "sbe_xip_validate(%p, %u) : "
+ "Given the link address (%u) and the "
+ "image size, the image wraps the address space\n",
+ i_image, i_size, linkAddress);
+ break;
+ }
+ if ((imageSize % SBE_XIP_FINAL_ALIGNMENT) != 0) {
+ rc = TRACE_ERRORX(SBE_XIP_ALIGNMENT_ERROR,
+ "sbe_xip_validate(%p, %u) : "
+ "The image size (%u) is not a multiple of %u\n",
+ i_image, i_size, imageSize,
+ SBE_XIP_FINAL_ALIGNMENT);
+ break;
+ }
+
+ // Validate that all sections appear to be within the image
+ // bounds, and are aligned correctly.
+
+ for (i = 0; i < SBE_XIP_SECTIONS; i++) {
+
+ offset = hostHeader.iv_section[i].iv_offset;
+ size = hostHeader.iv_section[i].iv_size;
+ alignment = hostHeader.iv_section[i].iv_alignment;
+
+ if ((offset > imageSize) ||
+ ((offset + size) > imageSize) ||
+ ((offset + size) < offset)) {
+ rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
+ "Section %d does not appear to be within "
+ "the bounds of the image\n"
+ "offset = %u, size = %u, image size = %u\n",
+ i, offset, size, imageSize);
+ break;
+ }
+ if ((offset % alignment) != 0) {
+ rc = TRACE_ERRORX(SBE_XIP_ALIGNMENT_ERROR,
+ "Section %d requires %d-byte initial "
+ "alignment but the section offset is %u\n",
+ i, alignment, offset);
+ break;
+ }
+ }
+ if (rc) break;
+
+ // If the TOC exists and the image is normalized, validate each TOC
+ // entry.
+
+ size = hostHeader.iv_section[SBE_XIP_SECTION_TOC].iv_size;
+ if (size != 0) {
+ if (xipNormalized(i_image)) {
+ rc = sbe_xip_map_toc(i_image, xipValidateTocEntry, 0);
+ if (rc) break;
+ }
+ }
+ } while (0);
+ return rc;
+}
+
+
+int
+sbe_xip_validate2(void* i_image, const uint32_t i_size, const uint32_t i_maskIgnores)
+{
+ SbeXipHeader hostHeader;
+ int rc = 0, i;
+ uint32_t linkAddress, imageSize, extent, offset, size;
+ uint8_t alignment;
+
+ sbe_xip_translate_header(&hostHeader, (SbeXipHeader*)i_image);
+
+ do {
+
+ // Validate C/Assembler constraints.
+
+ if (sizeof(SbeXipSection) != SIZE_OF_SBE_XIP_SECTION) {
+ rc = TRACE_ERRORX(SBE_XIP_BUG,
+ "C/Assembler size mismatch(%d/%d) "
+ "for SbeXipSection\n",
+ sizeof(SbeXipSection), SIZE_OF_SBE_XIP_SECTION);
+ break;
+ }
+
+ if (sizeof(SbeXipToc) != SIZE_OF_SBE_XIP_TOC) {
+ rc = TRACE_ERRORX(SBE_XIP_BUG,
+ "C/Assembler size mismatch(%d/%d) "
+ "for SbeXipToc\n",
+ sizeof(SbeXipToc), SIZE_OF_SBE_XIP_TOC);
+ break;
+ }
+
+ if (sizeof(SbeXipHashedToc) != SIZE_OF_SBE_XIP_HASHED_TOC) {
+ rc = TRACE_ERRORX(SBE_XIP_BUG,
+ "C/Assembler size mismatch(%d/%d) "
+ "for SbeXipHashedToc\n",
+ sizeof(SbeXipHashedToc),
+ SIZE_OF_SBE_XIP_HASHED_TOC);
+ break;
+ }
+
+ // Validate the image pointer and magic number
+
+ rc = xipQuickCheck(i_image, 0);
+ if (rc) break;
+
+ // Validate the image size
+
+ linkAddress = hostHeader.iv_linkAddress;
+ imageSize = hostHeader.iv_imageSize;
+ extent = linkAddress + imageSize;
+
+ if (imageSize < sizeof(SbeXipHeader)) {
+ rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
+ "sbe_xip_validate2(%p, %u) : "
+ "The image size recorded in the image "
+ "(%u) is smaller than the header size.\n",
+ i_image, i_size, imageSize);
+ break;
+ }
+ if (imageSize != i_size && !(i_maskIgnores & SBE_XIP_IGNORE_FILE_SIZE)) {
+ rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
+ "sbe_xip_validate2(%p, %u) : "
+ "The image size recorded in the image "
+ "(%u) does not match the i_size parameter.\n",
+ i_image, i_size, imageSize);
+ break;
+ }
+ if (extent <= linkAddress) {
+ rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
+ "sbe_xip_validate2(%p, %u) : "
+ "Given the link address (%u) and the "
+ "image size, the image wraps the address space\n",
+ i_image, i_size, linkAddress);
+ break;
+ }
+ if ((imageSize % SBE_XIP_FINAL_ALIGNMENT) != 0) {
+ rc = TRACE_ERRORX(SBE_XIP_ALIGNMENT_ERROR,
+ "sbe_xip_validate2(%p, %u) : "
+ "The image size (%u) is not a multiple of %u\n",
+ i_image, i_size, imageSize,
+ SBE_XIP_FINAL_ALIGNMENT);
+ break;
+ }
+
+ // Validate that all sections appear to be within the image
+ // bounds, and are aligned correctly.
+
+ for (i = 0; i < SBE_XIP_SECTIONS; i++) {
+
+ offset = hostHeader.iv_section[i].iv_offset;
+ size = hostHeader.iv_section[i].iv_size;
+ alignment = hostHeader.iv_section[i].iv_alignment;
+
+ if ((offset > imageSize) ||
+ ((offset + size) > imageSize) ||
+ ((offset + size) < offset)) {
+ rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
+ "Section %d does not appear to be within "
+ "the bounds of the image\n"
+ "offset = %u, size = %u, image size = %u\n",
+ i, offset, size, imageSize);
+ break;
+ }
+ if ((offset % alignment) != 0) {
+ rc = TRACE_ERRORX(SBE_XIP_ALIGNMENT_ERROR,
+ "Section %d requires %d-byte initial "
+ "alignment but the section offset is %u\n",
+ i, alignment, offset);
+ break;
+ }
+ }
+ if (rc) break;
+
+ // If the TOC exists and the image is normalized, validate each TOC
+ // entry.
+
+ size = hostHeader.iv_section[SBE_XIP_SECTION_TOC].iv_size;
+ if (size != 0) {
+ if (xipNormalized(i_image)) {
+ rc = sbe_xip_map_toc(i_image, xipValidateTocEntry, 0);
+ if (rc) break;
+ }
+ }
+ } while (0);
+ return rc;
+}
+
+
+// Normalization:
+//
+// 1. Normalize the TOC, unless the image is already normalized. The image
+// must be marked as normalized before sorting.
+//
+// 2. Sort the TOC.
+//
+// 3. Clear the section offsets of any empty sections to make the section
+// table reports less confusing.
+//
+// 4. Clear normalization status on any failure.
+
+int
+sbe_xip_normalize(void* io_image)
+{
+ int rc, i;
+ SbeXipSection section;
+ SbeXipToc* imageToc;
+ SbeXipHashedToc* fixedImageToc = NULL;
+ SbeXipHashedToc* fixedTocEntry = NULL;
+ size_t tocEntries = 0;
+ size_t fixedTocEntries = 0;
+ size_t fixedEntriesRemaining = 0;
+
+ do {
+ rc = xipQuickCheck(io_image, 0);
+ if (rc) break;
+
+ if (!xipNormalized(io_image)) {
+
+ rc = xipGetToc(io_image, &imageToc, &tocEntries, 0, 0);
+ if (rc) break;
+
+ rc = xipGetFixedToc(io_image, &fixedImageToc, &fixedTocEntries);
+ if (rc) break;
+
+ fixedTocEntry = fixedImageToc;
+ fixedEntriesRemaining = fixedTocEntries;
+
+ for (; tocEntries--; imageToc++) {
+ rc = xipNormalizeToc(io_image, imageToc,
+ &fixedTocEntry, &fixedEntriesRemaining);
+ if (rc) break;
+
+ }
+ if (rc) break;
+
+ if (fixedEntriesRemaining != 0) {
+ rc = TRACE_ERRORX(SBE_XIP_TOC_ERROR,
+ "Not enough TOC entries for .fixed");
+ break;
+ }
+
+ rc = xipHashCollision(fixedImageToc, fixedTocEntries);
+ if (rc) break;
+
+ ((SbeXipHeader*)io_image)->iv_normalized = 1;
+ }
+
+ rc = xipSortToc(io_image);
+ if (rc) break;
+
+ for (i = 0; i < SBE_XIP_SECTIONS; i++) {
+ rc = sbe_xip_get_section(io_image, i, &section);
+ if (rc) break;
+ if (section.iv_size == 0) {
+ xipSetSectionOffset(io_image, i, 0);
+ }
+ }
+ if (rc) break;
+
+ } while(0);
+
+ ((SbeXipHeader*)io_image)->iv_normalized = (rc == 0);
+
+ return rc;
+}
+
+
+int
+sbe_xip_image_size(void* io_image, uint32_t* o_size)
+{
+ int rc;
+
+ rc = xipQuickCheck(io_image, 0);
+ if (!rc) {
+ *o_size = xipImageSize(io_image);
+ }
+ return rc;
+}
+
+
+int
+sbe_xip_get_section(const void* i_image,
+ const int i_sectionId,
+ SbeXipSection* o_hostSection)
+{
+ int rc;
+ SbeXipSection *imageSection = NULL;
+
+ rc = xipGetSectionPointer(i_image, i_sectionId, &imageSection);
+
+ if (!rc) {
+ xipTranslateSection(o_hostSection, imageSection);
+ }
+
+ return rc;
+}
+
+
+// If the 'big' TOC is not present, search the mini-TOCs that only index the
+// .fixed and .header sections.
+
+int
+sbe_xip_find(void* i_image,
+ const char* i_id,
+ SbeXipItem* o_item)
+{
+ int rc;
+ SbeXipToc* toc;
+ SbeXipItem item, *pitem;
+ SbeXipSection* tocSection;
+
+ do {
+ rc = xipQuickCheck(i_image, 1);
+ if (rc) break;
+
+ rc = xipGetSectionPointer(i_image, SBE_XIP_SECTION_TOC, &tocSection);
+ if (rc) break;
+
+ if (tocSection->iv_size == 0) {
+ rc = xipFixedFind(i_image, i_id, o_item);
+ if (rc) {
+ rc = xipHeaderFind(i_image, i_id, o_item);
+ }
+ break;
+ }
+
+ if (xipSorted(i_image)) {
+ rc = xipBinarySearch(i_image, i_id, &toc);
+ } else {
+ rc = xipLinearSearch(i_image, i_id, &toc);
+ }
+ if (rc) break;
+
+ if (o_item) {
+ pitem = o_item;
+ } else {
+ pitem = &item;
+ }
+ rc = xipDecodeToc(i_image, toc, pitem);
+ if (rc) break;
+
+ } while (0);
+
+ return rc;
+}
+
+
+int
+sbe_xip_map_halt(void* io_image,
+ int (*i_fn)(void* io_image,
+ const uint64_t i_poreAddress,
+ const char* i_rcString,
+ void* io_arg),
+ void* io_arg)
+{
+ int rc;
+ SbeXipSection haltSection;
+ SbeXipHalt *halt;
+ uint32_t size;
+ uint32_t actualSize;
+
+ do {
+ rc = xipQuickCheck(io_image, 0);
+ if (rc) break;
+
+ rc = sbe_xip_get_section(io_image, SBE_XIP_SECTION_HALT, &haltSection);
+ if (rc) break;
+
+ halt = (SbeXipHalt*)((unsigned long)io_image + haltSection.iv_offset);
+ size = haltSection.iv_size;
+
+ while (size) {
+
+ rc = i_fn(io_image,
+ xipRevLe64(halt->iv_address),
+ halt->iv_string,
+ io_arg);
+ if (rc) break;
+
+ // The SbeXipHalt structure claims a 4-character string. The
+ // computation below computes the actual record size based on the
+ // actual length of the string, including the 0-byte termination.
+
+ actualSize = 8 + (((strlen(halt->iv_string) + 4) / 4) * 4);
+
+ if (size < actualSize) {
+ rc = TRACE_ERRORX(SBE_XIP_IMAGE_ERROR,
+ "The .halt section is improperly formed\n");
+ break;
+ }
+
+ size -= actualSize;
+ halt = (SbeXipHalt*)((unsigned long)halt + actualSize);
+ };
+
+ if (rc) break;
+
+ } while (0);
+
+ return rc;
+}
+
+
+typedef struct {
+ uint64_t iv_address;
+ const char* iv_string;
+} GetHaltStruct;
+
+
+XIP_STATIC int
+xipGetHaltMap(void* io_image,
+ const uint64_t i_poreAddress,
+ const char* i_rcString,
+ void* io_arg)
+{
+ int rc;
+
+ GetHaltStruct* s = (GetHaltStruct*)io_arg;
+
+ (void)io_image;
+
+ if (i_poreAddress == s->iv_address) {
+ s->iv_string = i_rcString;
+ rc = -1;
+ } else {
+ rc = 0;
+ }
+
+ return rc;
+}
+
+
+int
+sbe_xip_get_halt(void* io_image,
+ const uint64_t i_poreAddress,
+ const char** o_rcString)
+{
+ int rc;
+ GetHaltStruct s;
+
+ s.iv_address = i_poreAddress;
+ do {
+ rc = xipQuickCheck(io_image, 0);
+ if (rc) break;
+
+ rc = sbe_xip_map_halt(io_image, xipGetHaltMap, &s);
+ if (rc == 0) {
+ rc = TRACE_ERRORX(SBE_XIP_ITEM_NOT_FOUND,
+ "sbe_xip_get_halt: No HALT code is associated "
+ "with address " F0x012llx "\n", i_poreAddress);
+ } else if (rc < 0) {
+ *o_rcString = s.iv_string;
+ rc = 0;
+ }
+ } while (0);
+
+ return rc;
+}
+
+
+int
+sbe_xip_get_scalar(void *i_image, const char* i_id, uint64_t* o_data)
+{
+ int rc;
+ SbeXipItem item;
+
+ rc = sbe_xip_find(i_image, i_id, &item);
+ if (!rc) {
+ switch (item.iv_type) {
+ case SBE_XIP_UINT8:
+ *o_data = *((uint8_t*)(item.iv_imageData));
+ break;
+ case SBE_XIP_UINT32:
+ *o_data = xipRevLe32(*((uint32_t*)(item.iv_imageData)));
+ break;
+ case SBE_XIP_UINT64:
+ *o_data = xipRevLe64(*((uint64_t*)(item.iv_imageData)));
+ break;
+ case SBE_XIP_ADDRESS:
+ *o_data = item.iv_address;
+ break;
+ default:
+ rc = TRACE_ERROR(SBE_XIP_TYPE_ERROR);
+ break;
+ }
+ }
+ return rc;
+}
+
+
+int
+sbe_xip_get_element(void *i_image,
+ const char* i_id,
+ const uint32_t i_index,
+ uint64_t* o_data)
+{
+ int rc;
+ SbeXipItem item;
+
+ do {
+ rc = sbe_xip_find(i_image, i_id, &item);
+ if (rc) break;
+
+ if ((item.iv_elements != 0) && (i_index >= item.iv_elements)) {
+ rc = TRACE_ERROR(SBE_XIP_BOUNDS_ERROR);
+ break;
+ }
+
+ switch (item.iv_type) {
+ case SBE_XIP_UINT8:
+ *o_data = ((uint8_t*)(item.iv_imageData))[i_index];
+ break;
+ case SBE_XIP_UINT32:
+ *o_data = xipRevLe32(((uint32_t*)(item.iv_imageData))[i_index]);
+ break;
+ case SBE_XIP_UINT64:
+ *o_data = xipRevLe64(((uint64_t*)(item.iv_imageData))[i_index]);
+ break;
+ default:
+ rc = TRACE_ERROR(SBE_XIP_TYPE_ERROR);
+ break;
+ }
+ if (rc) break;
+
+ } while (0);
+ return rc;
+}
+
+
+int
+sbe_xip_get_string(void *i_image, const char* i_id, char** o_data)
+{
+ int rc;
+ SbeXipItem item;
+
+ rc = sbe_xip_find(i_image, i_id, &item);
+ if (!rc) {
+ switch (item.iv_type) {
+ case SBE_XIP_STRING:
+ *o_data = (char*)(item.iv_imageData);
+ break;
+ default:
+ rc = TRACE_ERROR(SBE_XIP_TYPE_ERROR);
+ break;
+ }
+ }
+ return rc;
+}
+
+
+int
+sbe_xip_read_uint64(const void *i_image,
+ const uint64_t i_poreAddress,
+ uint64_t* o_data)
+{
+ int rc;
+
+ do {
+ rc = xipQuickCheck(i_image, 0);
+ if (rc) break;
+
+ rc = xipValidatePoreAddress(i_image, i_poreAddress, 8);
+ if (rc) break;
+
+ if (i_poreAddress % 8) {
+ rc = TRACE_ERROR(SBE_XIP_ALIGNMENT_ERROR);
+ break;
+ }
+
+ *o_data =
+ xipRevLe64(*((uint64_t*)xipPore2Host(i_image, i_poreAddress)));
+
+ } while(0);
+
+ return rc;
+}
+
+
+int
+sbe_xip_set_scalar(void* io_image, const char* i_id, const uint64_t i_data)
+{
+ int rc;
+ SbeXipItem item;
+
+ rc = sbe_xip_find(io_image, i_id, &item);
+ if (!rc) {
+ switch(item.iv_type) {
+ case SBE_XIP_UINT8:
+ *((uint8_t*)(item.iv_imageData)) = (uint8_t)i_data;
+ break;
+ case SBE_XIP_UINT32:
+ *((uint32_t*)(item.iv_imageData)) = xipRevLe32((uint32_t)i_data);
+ break;
+ case SBE_XIP_UINT64:
+ *((uint64_t*)(item.iv_imageData)) = xipRevLe64((uint64_t)i_data);
+ break;
+ default:
+ rc = TRACE_ERROR(SBE_XIP_TYPE_ERROR);
+ break;
+ }
+ }
+ return rc;
+}
+
+
+int
+sbe_xip_set_element(void *i_image,
+ const char* i_id,
+ const uint32_t i_index,
+ const uint64_t i_data)
+{
+ int rc;
+ SbeXipItem item;
+
+ do {
+ rc = sbe_xip_find(i_image, i_id, &item);
+ if (rc) break;
+
+ if ((item.iv_elements != 0) && (i_index >= item.iv_elements)) {
+ rc = TRACE_ERROR(SBE_XIP_BOUNDS_ERROR);
+ break;
+ }
+
+ switch (item.iv_type) {
+ case SBE_XIP_UINT8:
+ ((uint8_t*)(item.iv_imageData))[i_index] = (uint8_t)i_data;
+ break;
+ case SBE_XIP_UINT32:
+ ((uint32_t*)(item.iv_imageData))[i_index] =
+ xipRevLe32((uint32_t)i_data);
+ break;
+ case SBE_XIP_UINT64:
+ ((uint64_t*)(item.iv_imageData))[i_index] =
+ xipRevLe64((uint64_t)i_data);
+ break;
+ default:
+ rc = TRACE_ERROR(SBE_XIP_TYPE_ERROR);
+ break;
+ }
+ if (rc) break;
+
+ } while (0);
+
+ return rc;
+}
+
+
+int
+sbe_xip_set_string(void *i_image, const char* i_id, const char* i_data)
+{
+ int rc;
+ SbeXipItem item;
+ char* dest;
+
+ rc = sbe_xip_find(i_image, i_id, &item);
+ if (!rc) {
+ switch (item.iv_type) {
+ case SBE_XIP_STRING:
+ dest = (char*)(item.iv_imageData);
+ if (strlen(dest) < strlen(i_data)) {
+ memcpy(dest, i_data, strlen(dest));
+ } else {
+ strcpy(dest, i_data);
+ }
+ break;
+ default:
+ rc = TRACE_ERROR(SBE_XIP_TYPE_ERROR);
+ break;
+ }
+ }
+ return rc;
+}
+
+
+int
+sbe_xip_write_uint64(void *io_image,
+ const uint64_t i_poreAddress,
+ const uint64_t i_data)
+{
+ int rc;
+
+ do {
+ rc = xipQuickCheck(io_image, 0);
+ if (rc) break;
+
+ rc = xipValidatePoreAddress(io_image, i_poreAddress, 8);
+ if (rc) break;
+
+ if (i_poreAddress % 8) {
+ rc = TRACE_ERROR(SBE_XIP_ALIGNMENT_ERROR);
+ break;
+ }
+
+ *((uint64_t*)xipPore2Host(io_image, i_poreAddress)) =
+ xipRevLe64(i_data);
+
+ } while(0);
+
+ return rc;
+}
+
+
+int
+sbe_xip_delete_section(void* io_image, const int i_sectionId)
+{
+ int rc, final;
+ SbeXipSection section;
+
+ do {
+ rc = xipQuickCheck(io_image, 1);
+ if (rc) break;
+
+ rc = sbe_xip_get_section(io_image, i_sectionId, &section);
+ if (rc) break;
+
+
+ // Deleting an empty section is a NOP. Otherwise the section must be
+ // the final section of the image. Update the sizes and re-establish
+ // the final image alignment.
+
+ if (section.iv_size == 0) break;
+
+ rc = xipFinalSection(io_image, &final);
+ if (rc) break;
+
+ if (final != i_sectionId) {
+ rc = TRACE_ERRORX(SBE_XIP_SECTION_ERROR,
+ "Attempt to delete non-final section %d\n",
+ i_sectionId);
+ break;
+ }
+
+ xipSetSectionOffset(io_image, i_sectionId, 0);
+ xipSetSectionSize(io_image, i_sectionId, 0);
+
+
+ // For cleanliness we also remove any alignment padding that had been
+ // appended between the now-last section and the deleted section, then
+ // re-establish the final alignment. The assumption is that all images
+ // always have the correct final alignment, so there is no way this
+ // could overflow a designated buffer space since the image size is
+ // the same or has been reduced.
+
+ rc = xipFinalSection(io_image, &final);
+ if (rc) break;
+
+ rc = sbe_xip_get_section(io_image, final, &section);
+ if (rc) break;
+
+ xipSetImageSize(io_image, section.iv_offset + section.iv_size);
+ xipFinalAlignment(io_image);
+
+ } while (0);
+
+ return rc;
+}
+
+
+#ifndef PPC_HYP
+
+// This API is not needed by PHYP procedures, and is elided since PHYP does
+// not support malloc().
+
+int
+sbe_xip_duplicate_section(const void* i_image,
+ const int i_sectionId,
+ void** o_duplicate,
+ uint32_t* o_size)
+{
+ SbeXipSection section;
+ int rc;
+
+ *o_duplicate = 0;
+
+ do {
+ rc = xipQuickCheck(i_image, 0);
+ if (rc) break;
+
+ rc = sbe_xip_get_section(i_image, i_sectionId, &section);
+ if (rc) break;
+
+ if (section.iv_size == 0) {
+ rc = TRACE_ERRORX(SBE_XIP_SECTION_ERROR,
+ "Attempt to duplicate empty section %d\n",
+ i_sectionId);
+ break;
+ }
+
+ *o_duplicate = malloc(section.iv_size);
+ *o_size = section.iv_size;
+
+ if (*o_duplicate == 0) {
+ rc = TRACE_ERROR(SBE_XIP_NO_MEMORY);
+ break;
+ }
+
+ memcpy(*o_duplicate,
+ xipHostAddressFromOffset(i_image, section.iv_offset),
+ section.iv_size);
+
+
+ } while (0);
+
+ if (rc) {
+ free(*o_duplicate);
+ *o_duplicate = 0;
+ *o_size = 0;
+ }
+
+ return rc;
+}
+
+#endif // PPC_HYP
+
+
+// The append must be done in such a way that if the append fails, the image
+// is not modified. This behavior is required by applications that
+// speculatively append until the allocation fails, but still require the
+// final image to be valid. To accomplish this the initial image size and
+// section statistics are captured at entry, and restored in the event of an
+// error.
+
+int
+sbe_xip_append(void* io_image,
+ const int i_sectionId,
+ const void* i_data,
+ const uint32_t i_size,
+ const uint32_t i_allocation,
+ uint32_t* o_sectionOffset)
+{
+ SbeXipSection section, initialSection;
+ int rc, final, restoreOnError;
+ void* hostAddress;
+ uint32_t pad;
+ uint32_t initialSize = 0;
+
+ do {
+ restoreOnError = 0;
+
+ rc = xipQuickCheck(io_image, 1);
+ if (rc) break;
+
+ rc = sbe_xip_get_section(io_image, i_sectionId, &section);
+ if (rc) break;
+
+ if (i_size == 0) break;
+
+ initialSection = section;
+ initialSize = xipImageSize(io_image);
+ restoreOnError = 1;
+
+ if (section.iv_size == 0) {
+
+ // The section is empty, and now becomes the final section. Pad
+ // the image to the specified section alignment. Note that the
+ // size of the previously final section does not change.
+
+ rc = xipPadImage(io_image, i_allocation, section.iv_alignment,
+ &pad);
+ if (rc) break;
+ section.iv_offset = xipImageSize(io_image);
+
+ } else {
+
+ // Otherwise, the section must be the final section in order to
+ // continue. Remove any padding from the image.
+
+ rc = xipFinalSection(io_image, &final);
+ if (rc) break;
+
+ if (final != i_sectionId) {
+ rc = TRACE_ERRORX(SBE_XIP_SECTION_ERROR,
+ "Attempt to append to non-final section "
+ "%d\n", i_sectionId);
+ break;
+ }
+ xipSetImageSize(io_image, section.iv_offset + section.iv_size);
+ }
+
+
+ // Make sure the allocated space won't overflow. Set the return
+ // parameter o_sectionOffset and copy the new data into the image (or
+ // simply clear the space).
+
+ if ((xipImageSize(io_image) + i_size) > i_allocation) {
+ rc = TRACE_ERROR(SBE_XIP_WOULD_OVERFLOW);
+ break;
+ }
+ if (o_sectionOffset != 0) {
+ *o_sectionOffset = section.iv_size;
+ }
+
+ hostAddress =
+ xipHostAddressFromOffset(io_image, xipImageSize(io_image));
+ if (i_data == 0) {
+ memset(hostAddress, 0, i_size);
+ } else {
+ memcpy(hostAddress, i_data, i_size);
+ }
+
+
+ // Update the image size and section table. Note that the final
+ // alignment may push out of the allocation.
+
+ xipSetImageSize(io_image, xipImageSize(io_image) + i_size);
+ xipFinalAlignment(io_image);
+
+ if (xipImageSize(io_image) > i_allocation) {
+ rc = TRACE_ERROR(SBE_XIP_WOULD_OVERFLOW);
+ break;
+ }
+
+ section.iv_size += i_size;
+
+ if (xipPutSection(io_image, i_sectionId, &section) != 0) {
+ rc = TRACE_ERROR(SBE_XIP_BUG); /* Can't happen */
+ break;
+ }
+
+
+ // Special case
+
+ if (i_sectionId == SBE_XIP_SECTION_TOC) {
+ ((SbeXipHeader*)io_image)->iv_tocSorted = 0;
+ }
+
+ } while (0);
+
+ if (rc && restoreOnError) {
+ if (xipPutSection(io_image, i_sectionId, &initialSection) != 0) {
+ rc = TRACE_ERROR(SBE_XIP_BUG); /* Can't happen */
+ }
+ xipSetImageSize(io_image, initialSize);
+ }
+
+ return rc;
+}
+
+
+int
+sbe_xip_section2pore(const void* i_image,
+ const int i_sectionId,
+ const uint32_t i_offset,
+ uint64_t* o_poreAddress)
+{
+ int rc;
+ SbeXipSection section;
+
+ do {
+ rc = xipQuickCheck(i_image, 0);
+ if (rc) break;
+
+ rc = sbe_xip_get_section(i_image, i_sectionId, &section);
+ if (rc) break;
+
+ if (section.iv_size == 0) {
+ rc = TRACE_ERROR(SBE_XIP_SECTION_ERROR);
+ break;
+ }
+
+ if (i_offset > (section.iv_offset + section.iv_size)) {
+ rc = TRACE_ERROR(SBE_XIP_INVALID_ARGUMENT);
+ break;
+ }
+
+ *o_poreAddress = xipLinkAddress(i_image) + section.iv_offset + i_offset;
+
+ if (*o_poreAddress % 4) {
+ rc = TRACE_ERROR(SBE_XIP_ALIGNMENT_ERROR);
+ break;
+ }
+
+ } while(0);
+
+ return rc;
+}
+
+
+int
+sbe_xip_pore2section(const void* i_image,
+ const uint64_t i_poreAddress,
+ int* i_section,
+ uint32_t* i_offset)
+{
+ int rc;
+
+ do {
+ rc = xipQuickCheck(i_image, 0);
+ if (rc) break;
+
+ rc = xipPore2Section(i_image, i_poreAddress, i_section, i_offset);
+
+ } while(0);
+
+ return rc;
+}
+
+
+int
+sbe_xip_pore2host(const void* i_image,
+ const uint64_t i_poreAddress,
+ void** o_hostAddress)
+{
+ int rc;
+
+ do {
+ rc = xipQuickCheck(i_image, 0);
+ if (rc) break;
+
+ if ((i_poreAddress < xipLinkAddress(i_image)) ||
+ (i_poreAddress >
+ (xipLinkAddress(i_image) + xipImageSize(i_image)))) {
+ rc = TRACE_ERROR(SBE_XIP_INVALID_ARGUMENT);
+ break;
+ }
+
+ *o_hostAddress =
+ xipHostAddressFromOffset(i_image,
+ i_poreAddress - xipLinkAddress(i_image));
+ } while(0);
+
+ return rc;
+}
+
+
+int
+sbe_xip_host2pore(const void* i_image,
+ void* i_hostAddress,
+ uint64_t* o_poreAddress)
+{
+ int rc;
+
+ do {
+ rc = xipQuickCheck(i_image, 0);
+ if (rc) break;
+
+ if ((i_hostAddress < i_image) ||
+ (i_hostAddress >
+ xipHostAddressFromOffset(i_image, xipImageSize(i_image)))) {
+ rc = TRACE_ERROR(SBE_XIP_INVALID_ARGUMENT);
+ break;
+ }
+
+ *o_poreAddress = xipLinkAddress(i_image) +
+ ((unsigned long)i_hostAddress - (unsigned long)i_image);
+ if (*o_poreAddress % 4) {
+ rc = TRACE_ERROR(SBE_XIP_ALIGNMENT_ERROR);
+ break;
+ }
+ } while(0);
+
+ return rc;
+}
+
+
+void
+sbe_xip_translate_header(SbeXipHeader* o_dest, const SbeXipHeader* i_src)
+{
+#ifndef _BIG_ENDIAN
+ int i;
+ SbeXipSection* destSection;
+ const SbeXipSection* srcSection;
+
+#if SBE_XIP_HEADER_VERSION != 8
+#error This code assumes the SBE-XIP header version 8 layout
+#endif
+
+ o_dest->iv_magic = xipRevLe64(i_src->iv_magic);
+ o_dest->iv_entryOffset = xipRevLe64(i_src->iv_entryOffset);
+ o_dest->iv_linkAddress = xipRevLe64(i_src->iv_linkAddress);
+ o_dest->iv_ptsVersion = xipRevLe64(i_src->iv_ptsVersion);
+
+ for (i = 0; i < 4; i++) {
+ o_dest->iv_reserved64[i] = 0;
+ }
+
+ for (i = 0, destSection = o_dest->iv_section,
+ srcSection = i_src->iv_section;
+ i < SBE_XIP_SECTIONS;
+ i++, destSection++, srcSection++) {
+ xipTranslateSection(destSection, srcSection);
+ }
+
+ o_dest->iv_imageSize = xipRevLe32(i_src->iv_imageSize);
+ o_dest->iv_buildDate = xipRevLe32(i_src->iv_buildDate);
+ o_dest->iv_buildTime = xipRevLe32(i_src->iv_buildTime);
+
+ for (i = 0; i < 5; i++) {
+ o_dest->iv_reserved32[i] = 0;
+ }
+
+ o_dest->iv_headerVersion = i_src->iv_headerVersion;
+ o_dest->iv_normalized = i_src->iv_normalized;
+ o_dest->iv_tocSorted = i_src->iv_tocSorted;
+
+ for (i = 0; i < 3; i++) {
+ o_dest->iv_reserved8[i] = 0;
+ }
+
+ memcpy(o_dest->iv_buildUser, i_src->iv_buildUser,
+ sizeof(i_src->iv_buildUser));
+ memcpy(o_dest->iv_buildHost, i_src->iv_buildHost,
+ sizeof(i_src->iv_buildHost));
+ memcpy(o_dest->iv_reservedChar, i_src->iv_reservedChar,
+ sizeof(i_src->iv_reservedChar));
+
+#else
+ if (o_dest != i_src) {
+ *o_dest = *i_src;
+ }
+#endif /* _BIG_ENDIAN */
+}
+
+
+int
+sbe_xip_map_toc(void* io_image,
+ int (*i_fn)(void* io_image,
+ const SbeXipItem* i_item,
+ void* io_arg),
+ void* io_arg)
+{
+ int rc;
+ SbeXipToc *imageToc;
+ SbeXipItem item;
+ size_t entries;
+
+ do {
+ rc = xipQuickCheck(io_image, 0);
+ if (rc) break;
+
+ rc = xipGetToc(io_image, &imageToc, &entries, 0, 0);
+ if (rc) break;
+
+ for (; entries--; imageToc++) {
+ rc = xipDecodeToc(io_image, imageToc, &item);
+ if (rc) break;
+ rc = i_fn(io_image, &item, io_arg);
+ if (rc) break;
+ }
+ } while(0);
+
+ return rc;
+}
diff --git a/roms/skiboot/libpore/sbe_xip_image.h b/roms/skiboot/libpore/sbe_xip_image.h
new file mode 100644
index 000000000..0b871a769
--- /dev/null
+++ b/roms/skiboot/libpore/sbe_xip_image.h
@@ -0,0 +1,1789 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/hwpf/hwp/build_winkle_images/p8_slw_build/sbe_xip_image.h $ */
+/* */
+/* OpenPOWER HostBoot Project */
+/* */
+/* Contributors Listed Below - COPYRIGHT 2012,2015 */
+/* [+] International Business Machines Corp. */
+/* */
+/* */
+/* Licensed under the Apache License, Version 2.0 (the "License"); */
+/* you may not use this file except in compliance with the License. */
+/* You may obtain a copy of the License at */
+/* */
+/* http://www.apache.org/licenses/LICENSE-2.0 */
+/* */
+/* Unless required by applicable law or agreed to in writing, software */
+/* distributed under the License is distributed on an "AS IS" BASIS, */
+/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */
+/* implied. See the License for the specific language governing */
+/* permissions and limitations under the License. */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __SBE_XIP_IMAGE_H
+#define __SBE_XIP_IMAGE_H
+
+// $Id: sbe_xip_image.h,v 1.26 2015/07/29 23:40:17 cmolsen Exp $
+// $Source: /afs/awd/projects/eclipz/KnowledgeBase/.cvsroot/eclipz/chips/p8/working/procedures/ipl/sbe/sbe_xip_image.h,v $
+//-----------------------------------------------------------------------------
+// *! (C) Copyright International Business Machines Corp. 2011
+// *! All Rights Reserved -- Property of IBM
+// *! *** ***
+//-----------------------------------------------------------------------------
+// *! OWNER NAME: Bishop Brock Email: bcbrock@us.ibm.com
+//------------------------------------------------------------------------------
+
+/// \file sbe_xip_image.h
+/// \brief Everything related to creating and manipulating SBE-XIP binary
+/// images.
+
+#include "fapi_sbe_common.H"
+
+/// Current version (fields, layout, sections) of the SBE_XIP header
+///
+/// If any changes are made to this file or to sbe_xip_header.H, please update
+/// the header version and follow-up on all of the error messages.
+
+#define SBE_XIP_HEADER_VERSION 8
+
+/// \defgroup sbe_xip_magic_numbers SBE-XIP magic numbers
+///
+/// An SBE-XIP magic number is a 64-bit constant. The 4 high-order bytes
+/// contain the ASCII characters "XIP " and identify the image as an SBE-XIP
+/// image, while the 4 low-order bytes identify the type of the image.
+///
+/// @{
+
+#define SBE_XIP_MAGIC 0x58495020 // "XIP "
+#define SBE_BASE_MAGIC ULL(0x5849502042415345) // "XIP BASE"
+#define SBE_SEEPROM_MAGIC ULL(0x584950205345504d) // "XIP SEPM"
+#define SBE_CENTAUR_MAGIC ULL(0x58495020434e5452) // "XIP CNTR"
+
+/// @}
+
+
+/// \defgroup sbe_xip_sections SBE-XIP Image Section Indexes
+///
+/// These constants define the order that the SbeXipSection structures appear
+/// in the header, which is not necessarily the order the sections appear in
+/// the binary image. Given that SBE-XIP image contents are tightly
+/// controlled, we use this simple indexing scheme for the allowed sections
+/// rather than a more general approach, e.g., allowing arbitrary sections
+/// identified by their names.
+///
+/// @{
+
+// -*- DO NOT REORDER OR EDIT THIS SET OF CONSTANTS WITHOUT ALSO EDITING -*-
+// -*- THE ASSEMBLER LAYOUT IN sbe_xip_header.H. -*-
+
+#define SBE_XIP_SECTION_HEADER 0
+#define SBE_XIP_SECTION_FIXED 1
+#define SBE_XIP_SECTION_FIXED_TOC 2
+#define SBE_XIP_SECTION_IPL_TEXT 3
+#define SBE_XIP_SECTION_IPL_DATA 4
+#define SBE_XIP_SECTION_TEXT 5
+#define SBE_XIP_SECTION_DATA 6
+#define SBE_XIP_SECTION_TOC 7
+#define SBE_XIP_SECTION_STRINGS 8
+#define SBE_XIP_SECTION_HALT 9
+#define SBE_XIP_SECTION_PIBMEM0 10
+#define SBE_XIP_SECTION_DCRINGS 11
+#define SBE_XIP_SECTION_RINGS 12
+#define SBE_XIP_SECTION_SLW 13
+#define SBE_XIP_SECTION_FIT 14
+#define SBE_XIP_SECTION_FFDC 15
+
+#define SBE_XIP_SECTIONS 16
+
+/// @}
+
+
+/// \defgroup sbe_xip_validate() ignore masks.
+///
+/// These defines, when matched in sbe_xip_validate(), cause the validation
+/// to skip the check of the corresponding property. The purpose is to more
+/// effectively debug images that may be damaged and which have excess info
+/// before or after the image. The latter will be the case when dumping the
+/// image as a memory block without knowing where the image starts and ends.
+///
+/// @{
+
+#define SBE_XIP_IGNORE_FILE_SIZE (uint32_t)0x00000001
+#define SBE_XIP_IGNORE_ALL (uint32_t)0x80000000
+
+/// @}
+
+
+#ifndef __ASSEMBLER__
+
+/// Applications can expand this macro to create an array of section names.
+#define SBE_XIP_SECTION_NAMES(var) \
+ const char* var[] = { \
+ ".header", \
+ ".fixed", \
+ ".fixed_toc", \
+ ".ipl_text", \
+ ".ipl_data", \
+ ".text", \
+ ".data", \
+ ".toc", \
+ ".strings", \
+ ".halt", \
+ ".pibmem0", \
+ ".dcrings", \
+ ".rings", \
+ ".slw", \
+ ".fit", \
+ ".ffdc", \
+ }
+
+/// Applications can use this macro to safely index the array of section
+/// names.
+#define SBE_XIP_SECTION_NAME(var, n) \
+ ((((n) < 0) || ((n) > (int)(sizeof(var) / sizeof(char*)))) ? \
+ "Bug : Invalid SBE-XIP section name" : var[n])
+
+
+#endif /* __ASSEMBLER__ */
+
+
+/// Maximum section alignment for SBE-XIP sections
+#define SBE_XIP_MAX_SECTION_ALIGNMENT 128
+
+/// \defgroup sbe_xip_toc_types SBE-XIP Table of Contents data types
+///
+/// These are the data types stored in the \a iv_type field of the SbeXipToc
+/// objects. These must be defined as manifest constants because they are
+/// required to be recognized as manifest constants in C (as opposed to C++)
+/// code.
+///
+/// NB: The 0x0 code is purposefully left undefined to catch bugs.
+///
+/// @{
+
+/// Data is a single unsigned byte
+#define SBE_XIP_UINT8 0x01
+
+/// Data is a 32-bit unsigned integer
+#define SBE_XIP_UINT32 0x02
+
+/// Data is a 64-bit unsigned integer
+#define SBE_XIP_UINT64 0x03
+
+/// Data is a 0-byte terminated ASCII string
+#define SBE_XIP_STRING 0x04
+
+/// Data is an address
+#define SBE_XIP_ADDRESS 0x05
+
+/// The maximum type number
+#define SBE_XIP_MAX_TYPE_INDEX 0x05
+
+/// Applications can expand this macro to get access to string forms of the
+/// SBE-XIP data types if desired.
+#define SBE_XIP_TYPE_STRINGS(var) \
+ const char* var[] = { \
+ "Illegal 0 Code", \
+ "SBE_XIP_UINT8", \
+ "SBE_XIP_UINT32", \
+ "SBE_XIP_UINT64", \
+ "SBE_XIP_STRING", \
+ "SBE_XIP_ADDRESS", \
+ }
+
+/// Applications can expand this macro to get access to abbreviated string
+/// forms of the SBE-XIP data types if desired.
+#define SBE_XIP_TYPE_ABBREVS(var) \
+ const char* var[] = { \
+ "Illegal 0 Code", \
+ "u8 ", \
+ "u32", \
+ "u64", \
+ "str", \
+ "adr", \
+ }
+
+/// Applications can use this macro to safely index either array of SBE-XIP
+/// type strings.
+#define SBE_XIP_TYPE_STRING(var, n) \
+ (((n) > (sizeof(var) / sizeof(char*))) ? \
+ "Invalid SBE-XIP type specification" : var[n])
+
+/// @}
+
+
+/// Final alignment constraint for SBE-XIP images.
+///
+/// PORE images are required to be multiples of 8 bytes in length, to
+/// guarantee that the PoreVe will be able to complete any 8-byte load/store.
+#define SBE_XIP_FINAL_ALIGNMENT 8
+
+
+////////////////////////////////////////////////////////////////////////////
+// C Definitions
+////////////////////////////////////////////////////////////////////////////
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if 0
+} /* So __cplusplus doesn't mess w/auto-indent */
+#endif
+
+/// SBE-XIP Section information
+///
+/// This structure defines the data layout of section table entries in the
+/// SBE-XIP image header.
+
+// -*- DO NOT REORDER OR EDIT THIS STRUCTURE DEFINITION WITHOUT ALSO -*-
+// -*- EDITING THE ASSEMBLER LAYOUT IN sbe_xip_header.H -*-
+
+typedef struct {
+
+ /// The offset (in bytes) of the section from the beginning of the image
+ ///
+ /// In normalized images the section offset will always be 0 if the
+ /// section size is also 0.
+ uint32_t iv_offset;
+
+ /// The size of the section in bytes, exclusive of alignment padding
+ ///
+ /// This is the size of the program-significant data in the section,
+ /// exclusive of any alignment padding or reserved or extra space. The
+ /// alignment padding (reserved space) is not represented explicitly, but
+ /// is only implied by the offset of any subsequent non-empty section, or
+ /// in the case of the final section in the image, the image size.
+ ///
+ /// Regardless of the \a iv_offset, if the \a iv_size of a section is 0 it
+ /// should be considered "not present" in the image. In normalized images
+ /// the section offset will always be 0 if the section size is also 0.
+ uint32_t iv_size;
+
+ /// The required initial alignment for the section offset
+ ///
+ /// The PORE and the applications using SBE-XIP images have strict
+ /// alignment/padding requirements. The PORE does not handle any type of
+ /// unaligned instruction or data fetches. Some sections and subsections
+ /// must also be POWER cache-line aligned. The \a iv_alignment applies to
+ /// the first byte of the section. PORE images are also required to be
+ /// multiples of 8 bytes in length, to guarantee that the PoreVe will be
+ /// able to complete any 8-byte load/store. These constraints are checked
+ /// by sbe_xip_validate() and enforced by sbe_xip_append(). The alignment
+ /// constraints may force a section to be padded, which may create "holes"
+ /// in the image as explained in the comments for the \a iv_size field.
+ ///
+ /// Note that alignment constraints are always checked relative to the
+ /// first byte of the image for in-memory images, not relative to the host
+ /// address. Alignment specifications are required to be a power-of-2.
+ uint8_t iv_alignment;
+
+ /// Reserved structure alignment padding; Pad to 12 bytes
+ uint8_t iv_reserved8[3];
+
+} SbeXipSection;
+
+/// The SbeXipSection structure is created by assembler code and is expected
+/// to have the same size in C code. This constraint is checked in
+/// sbe_xip_validate().
+#define SIZE_OF_SBE_XIP_SECTION 12
+
+
+/// SBE-XIP binary image header
+///
+/// This header occupies the initial bytes of an SBE-XIP binary image.
+/// The header contents are documented here, however the structure is actually
+/// defined in the file sbe_xip_header.S, and these two definitions must be
+/// kept consistent.
+///
+/// The header is a fixed-format representation of the most critical
+/// information about the image. The large majority of information about the
+/// image and its contents are available through the searchable table of
+/// contents. PORE code itself normally accesses the data directly through
+/// global symbols.
+///
+/// The header only contains information 1) required by OTPROM code (e.g., the
+/// entry point); 2) required by search and updating APIs (e.g., the
+/// locations and sizes of all of the sections.); a few pieces of critical
+/// meta-data (e.g., information about the image build process).
+///
+/// Any entries that are accessed by PORE code are required to be 64 bits, and
+/// will appear at the beginning of the header.
+///
+/// The header also contains bytewise offsets and sizes of all of the sections
+/// that are assembled to complete the image. The offsets are relative to the
+/// start of the image (where the header is loaded). The sizes include any
+/// padding inserted by the link editor to guarantee section alignment.
+///
+/// Every field of the header is also accesssible through the searchable table
+/// of contents as documented in sbe_xip_header.S.
+
+// -*- DO NOT REORDER OR EDIT THIS STRUCTURE DEFINITION WITHOUT ALSO -*-
+// -*- EDITING THE ASSEMBLER LAYOUT IN sbe_xip_header.S, AND WITHOUT -*-
+// -*- UPDATING THE sbe_xip_translate_header() API IN sbe_xip_image.c. -*-
+
+typedef struct {
+
+ //////////////////////////////////////////////////////////////////////
+ // Identification - 8-byte aligned; 8 entries
+ //////////////////////////////////////////////////////////////////////
+
+ /// Contains SBE_XIP_MAGIC to identify an SBE-XIP image
+ uint64_t iv_magic;
+
+ /// The offset of the SBE-XIP entry point from the start of the image
+ uint64_t iv_entryOffset;
+
+ /// The base address used to link the image, as a full relocatable PORE
+ /// address
+ uint64_t iv_linkAddress;
+
+ /// PTS version
+ uint64_t iv_ptsVersion;
+
+ /// Reserved for future expansion
+ uint64_t iv_reserved64[4];
+
+ //////////////////////////////////////////////////////////////////////
+ // Section Table - 4-byte aligned; 16 entries
+ //////////////////////////////////////////////////////////////////////
+
+ SbeXipSection iv_section[SBE_XIP_SECTIONS];
+
+ //////////////////////////////////////////////////////////////////////
+ // Other information - 4-byte aligned; 8 entries
+ //////////////////////////////////////////////////////////////////////
+
+ /// The size of the image (including padding) in bytes
+ uint32_t iv_imageSize;
+
+ /// Build date generated by `date +%Y%m%d`, e.g., 20110630
+ uint32_t iv_buildDate;
+
+ /// Build time generated by `date +%H%M`, e.g., 0756
+ uint32_t iv_buildTime;
+
+ /// Reserved for future expansion
+ uint32_t iv_reserved32[5];
+
+ //////////////////////////////////////////////////////////////////////
+ // Other Information - 1-byte aligned; 8 entries
+ //////////////////////////////////////////////////////////////////////
+
+ /// Header format version number
+ uint8_t iv_headerVersion;
+
+ /// Indicates whether the image has been normalized (0/1)
+ uint8_t iv_normalized;
+
+ /// Indicates whether the TOC has been sorted to speed searching (0/1)
+ uint8_t iv_tocSorted;
+
+ /// Reserved for future expansion
+ uint8_t iv_reserved8[5];
+
+ //////////////////////////////////////////////////////////////////////
+ // Strings; 64 characters allocated
+ //////////////////////////////////////////////////////////////////////
+
+ /// Build user, generated by `id -un`
+ char iv_buildUser[16];
+
+ /// Build host, generated by `hostname`
+ char iv_buildHost[24];
+
+ /// Reserved for future expansion
+ char iv_reservedChar[24];
+
+} SbeXipHeader;
+
+
+/// A C-structure form of the SBE-XIP Table of Contents (TOC) entries
+///
+/// The .toc section consists entirely of an array of these structures.
+/// TOC entries are never accessed by PORE code.
+///
+/// These structures store indexing information for global data required to be
+/// manipulated by external tools. The actual data is usually allocated in a
+/// data section and manipulated by the SBE code using global or local symbol
+/// names. Each TOC entry contains a pointer to a keyword string naming the
+/// data, the address of the data (or the data itself), the data type,
+/// meta-information about the data, and for vectors the vector size.
+
+// -*- DO NOT REORDER OR EDIT THIS STRUCTURE DEFINITION WITHOUT ALSO -*-
+// -*- EDITING THE ASSEMBLER MACROS (BELOW) THAT CREATE THE TABLE OF -*-
+// -*- CONTENTS ENTRIES. -*-
+
+typedef struct {
+
+ /// A pointer to a 0-byte terminated ASCII string identifying the data.
+ ///
+ /// When allocated by the .xip_toc macro this is a pointer to the string
+ /// form of the symbol name for the global or local symbol associated with
+ /// the data which is allocated in the .strings section. This pointer is
+ /// not aligned.
+ ///
+ /// When the image is normalized this pointer is replaced by the offset of
+ /// the string in the .strings section.
+ uint32_t iv_id;
+
+ /// A 32-bit pointer locating the data
+ ///
+ /// This field is initially populated by the link editor. For scalar,
+ /// vector and string types this is the final relocated address of the
+ /// first byte of the data. For address types, this is the relocated
+ /// address. When the image is normalized, these addresses are converted
+ /// into the equivalent offsets from the beginning of the section holding
+ /// the data.
+ uint32_t iv_data;
+
+ /// The type of the data; See \ref sbe_xip_toc_types.
+ uint8_t iv_type;
+
+ /// The section containing the data; See \ref sbe_xip_sections.
+ uint8_t iv_section;
+
+ /// The number of elements for vector types, otherwise 1 for scalar types
+ /// and addresses.
+ ///
+ /// Vectors are naturally limited in size, e.g. to the number of cores,
+ /// chips in a node, DD-levels etc. If \a iv_elements is 0 then no bounds
+ /// checking is done on get/set accesses of the data.
+ uint8_t iv_elements;
+
+ /// Structure alignment padding; Pad to 12 bytes
+ uint8_t iv_pad;
+
+} SbeXipToc;
+
+/// The SbeXipToc structure is created by assembler code and is expected
+/// to have the same size in C code. This constraint is checked in
+/// sbe_xip_validate().
+#define SIZE_OF_SBE_XIP_TOC 12
+
+
+/// A C-structure form of hashed SBE-XIP Table of Contents (TOC) entries
+///
+/// This structure was introduced in order to allow a small TOC for the .fixed
+/// section to support minimum-sized SEEPROM images in which the global TOC
+/// and all strings have been stripped out. In this structure the index
+/// string has been replaced by a 32-bit hash, and there is no longer a record
+/// of the original data name other then the hash. The section of the data is
+/// assumed to be .fixed, with a maximum 16-bit offset.
+///
+/// These structures are created when entries are made in the .fixed section.
+/// They are created empty, then filled in during image normalization.
+///
+/// This structure allows the sbe_xip_get*() and sbe_xip_set*() APIs to work
+/// even on highly-stripped SEEPROM images.
+
+typedef struct {
+
+ /// A 32-bit hash (FNV-1a) of the Id string.
+ uint32_t iv_hash;
+
+ /// The offset in bytes from the start of the (implied) section of the data
+ uint16_t iv_offset;
+
+ /// The type of the data; See \ref sbe_xip_toc_types.
+ uint8_t iv_type;
+
+ /// The number of elements for vector types, otherwise 1 for scalar types
+ /// and addresses.
+ ///
+ /// Vectors are naturally limited in size, e.g. to the number of cores,
+ /// chips in a node, DD-levels etc. If \a iv_elements is 0 then no bounds
+ /// checking is done on get/set accesses of the data.
+ uint8_t iv_elements;
+
+} SbeXipHashedToc;
+
+/// The SbeXipHashedToc structure is created by assembler code and is expected
+/// to have the same size in C code. This constraint is checked in
+/// sbe_xip_validate().
+#define SIZE_OF_SBE_XIP_HASHED_TOC 8
+
+
+/// A decoded TOC entry for use by applications
+///
+/// This structure is a decoded form of a normalized TOC entry, filled in by
+/// the sbe_xip_decode_toc() and sbe_xip_find() APIs. This structure is
+/// always returned with data elements in host-endian format.
+///
+/// In the event that the TOC has been removed from the image, this structure
+/// will also be returned by sbe_xip_find() with information populated from
+/// the .fixed_toc section if possible. In this case the field \a iv_partial
+/// will be set and only the fields \a iv_address, \a iv_imageData, \a iv_type
+/// and \a iv_elements will be populated (all other fields will be set to 0).
+///
+/// \note Only special-purpose applications will ever need to use this
+/// structure given that the higher-level APIs sbe_xip_get_*() and
+/// sbe_xip_set_*() are provided and should be used if possible, especially
+/// given that the information may be truncated as described above.
+
+typedef struct {
+
+ /// A pointer to the associated TOC entry as it exists in the image
+ ///
+ /// If \a iv_partial is set this field is returned as 0.
+ SbeXipToc* iv_toc;
+
+ /// The full relocatable PORE address
+ ///
+ /// All relocatable addresses are computed from the \a iv_linkAddress
+ /// stored in the header. For scalar and string data, this is the
+ /// relocatable address of the data. For address-only entries, this is
+ /// the indexed address itself.
+ uint64_t iv_address;
+
+ /// A host pointer to the first byte of text or data within the image
+ ///
+ /// For scalar or string types this is a host pointer to the first byte of
+ /// the data. For code pointers (addresses) this is host pointer to the
+ /// first byte of code. Note that any use of this field requires the
+ /// caller to handle conversion of the data to host endian-ness if
+ /// required. Only 8-bit and string data can be used directly on all
+ /// hosts.
+ void* iv_imageData;
+
+ /// The item name
+ ///
+ /// This is a pointer in host memory to a string that names the TOC entry
+ /// requested. This field is set to a pointer to the ID string of the TOC
+ /// entry inside the image. If \a iv_partial is set this field is returned
+ /// as 0.
+ char* iv_id;
+
+ /// The data type, one of the SBE_XIP_* constants
+ uint8_t iv_type;
+
+ /// The number of elements in a vector
+ ///
+ /// This field is set from the TOC entry when the TOC entry is
+ /// decoded. This value is stored as 1 for scalar declarations, and may be
+ /// set to 0 for vectors with large or undeclared sizes. Otherwise it is
+ /// used to bounds check indexed accesses.
+ uint8_t iv_elements;
+
+ /// Is this record only partially populated?
+ ///
+ /// This field is set to 0 normally, and only set to 1 if a lookup is made
+ /// in an image that only has the fixed TOC and the requested Id hashes to
+ /// the fixed TOC.
+ uint8_t iv_partial;
+
+} SbeXipItem;
+
+
+/// Prototype entry in the .halt section
+///
+/// The .halt section is generated by the 'reqhalt' macro. This structure
+/// associates the address of each halt with the string form of the FAPI
+/// return code associated with the halt. The string form is used because the
+/// FAPI error return code is not constant. The .halt section is 4-byte
+/// aligned, and each address/string entry is always padded to a multiple of 4
+/// bytes.
+///
+/// In the .halt section the \a iv_string may be any length, thus the size of
+/// each actual record is variable (although guaranteed to always be a
+/// multiple of 4 bytes). Although the C compiler might natuarlly align
+/// instances of this structure on a 64-bit boundary, the APIs that allow
+/// access to the .halt section assume that the underlying machine can do
+/// non-aligned loads from a pointer to this structure.
+
+typedef struct {
+
+ /// The 64-bit relocatable address of the halt
+ ///
+ /// This is the address found in the PC (Status Register bits 16:63) when
+ /// the PORE halts. The full 64-bit form is used rather than the simple
+ /// 32-bit offset to support merging SEEPROM and PIBMEM .halt sections in
+ /// the SEEPROM IPL images.
+ uint64_t iv_address;
+
+ /// A C-prototype for a variable-length 0-terminated ASCII string
+ ///
+ /// This is a prototype only to simplify C programming. The actual string
+ /// may be any length.
+ char iv_string[4];
+
+} SbeXipHalt;
+
+
+/// Validate an SBE-XIP image
+///
+/// \param[in] i_image A pointer to an SBE-XIP image in host memory.
+///
+/// \param[in] i_size The putative size of the image
+///
+/// \param[in] i_maskIgnores Array of ignore bits representing which properties
+/// should not be checked for in sbe_xip_validate2().
+///
+/// This API should be called first by all applications that manipulate
+/// SBE-XIP images in host memory. The magic number is validated, and
+/// the image is checked for consistency of the section table and table of
+/// contents. The \a iv_imageSize field of the header must also match the
+/// provided \a i_size parameter. Validation does not modify the image.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_validate(void* i_image, const uint32_t i_size);
+
+int
+sbe_xip_validate2(void* i_image, const uint32_t i_size, const uint32_t i_maskIgnores);
+
+
+/// Normalize the SBE-XIP image
+///
+/// \param[in] io_image A pointer to an SBE-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections.
+///
+/// SBE-XIP images must be normalized before any other APIs are allowed to
+/// operate on the image. Since normalization modifies the image, an explicit
+/// call to normalize the image is required. Briefly, normalization modifies
+/// the TOC entries created by the final link to simplify search, updates,
+/// modification and relocation of the image. Normalization is explained in
+/// the written documentation of the SBE-XIP binary format. Normalization does
+/// not modify the size of the image.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_normalize(void* io_image);
+
+
+/// Return the size of an SBE-XIP image from the image header
+///
+/// \param[in] i_image A pointer to an SBE-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections.
+///
+/// \param[out] o_size A pointer to a variable returned as the size of the
+/// image in bytes, as recorded in the image header.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_image_size(void* i_image, uint32_t* o_size);
+
+
+/// Locate a section table entry and translate into host format
+///
+/// \param[in] i_image A pointer to an SBE-XIP image in host memory.
+///
+/// \param[in] i_sectionId Identifies the section to be queried. See \ref
+/// sbe_xip_sections.
+///
+/// \param[out] o_hostSection Updated to contain the section table entry
+/// translated to host byte order.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_get_section(const void* i_image,
+ const int i_sectionId,
+ SbeXipSection* o_hostSection);
+
+
+/// Endian translation of an SbeXipHeader object
+///
+/// \param[out] o_hostHeader The destination object.
+///
+/// \param[in] i_imageHeader The source object.
+///
+/// Translation of a SbeXipHeader includes translation of all data members
+/// including traslation of the embedded section table. This translation
+/// works even if \a o_src == \a o_dest, i.e., in the destructive case.
+void
+sbe_xip_translate_header(SbeXipHeader* o_hostHeader,
+ const SbeXipHeader* i_imageHeader);
+
+
+/// Get scalar data from an SBE-XIP image
+///
+/// \param[in] i_image A pointer to an SBE-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections. The image is
+/// also required to have been normalized.
+///
+/// \param[in] i_id A pointer to a 0-terminated ASCII string naming the item
+/// requested.
+///
+/// \param[out] o_data A pointer to an 8-byte integer to receive the scalar
+/// data. Assuming the item is located this variable is assigned by the call.
+/// In the event of an error the final state of \a o_data is not specified.
+///
+/// This API searches the SBE-XIP Table of Contents (TOC) for the item named
+/// \a i_id, assigning \a o_data from the image if the item is found and is a
+/// scalar value. Scalar values include 8- 32- and 64-bit integers and PORE
+/// addresses. Image data smaller than 64 bits are extracted as unsigned
+/// types, and it is the caller's responsibility to cast or convert the
+/// returned data as appropriate.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_get_scalar(void *i_image, const char* i_id, uint64_t* o_data);
+
+
+/// Get an integral element from a vector held in an SBE-XIP image
+///
+/// \param[in] i_image A pointer to an SBE-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections. The image is
+/// also required to have been normalized.
+///
+/// \param[in] i_id A pointer to a 0-terminated ASCII string naming the item
+/// requested.
+///
+/// \param[in] i_index The index of the vector element to return.
+///
+/// \param[out] o_data A pointer to an 8-byte integer to receive the
+/// data. Assuming the item is located this variable is assigned by the call.
+/// In the event of an error the final state of \a o_data is not specified.
+///
+/// This API searches the SBE-XIP Table of Contents (TOC) for the \a i_index
+/// element of the item named \a i_id, assigning \a o_data from the image if
+/// the item is found, is a vector of an integral type, and the \a i_index is
+/// in bounds. Vector elements smaller than 64 bits are extracted as unsigned
+/// types, and it is the caller's responsibility to cast or convert the
+/// returned data as appropriate.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_get_element(void *i_image,
+ const char* i_id,
+ const uint32_t i_index,
+ uint64_t* o_data);
+
+
+/// Get string data from an SBE-XIP image
+///
+/// \param[in] i_image A pointer to an SBE-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections. The image is
+/// also required to have been normalized.
+///
+/// \param[in] i_id A pointer to a 0-terminated ASCII string naming the item
+/// requested.
+///
+/// \param[out] o_data A pointer to a character pointer. Assuming the
+/// item is located this variable is assigned by the call to point to the
+/// string as it exists in the \a i_image. In the event of an error the final
+/// state of \a o_data is not specified.
+///
+/// This API searches the SBE-XIP Table of Contents (TOC) for the item named
+/// \a i_id, assigning \a o_data if the item is found and is a string. It is
+/// the caller's responsibility to copy the string from the \a i_image memory
+/// space if necessary.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_get_string(void *i_image, const char* i_id, char** o_data);
+
+
+/// Directly read 64-bit data from the image based on a PORE address
+///
+/// \param[in] i_image A pointer to an SBE-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections.
+///
+/// \param[in] i_poreAddress A relocatable PORE address contained in the
+/// image, presumably of an 8-byte data area. The \a i_poreAddress is
+/// required to be 8-byte aligned, otherwise the SBE_XIP_ALIGNMENT_ERROR code
+/// is returned.
+///
+/// \param[out] o_data The 64 bit data in host format that was found at \a
+/// i_poreAddress.
+///
+/// This API is provided for applications that need to manipulate SBE-XIP
+/// images in terms of their relocatable PORE addresses. The API checks that
+/// the \a i_poreAddress is properly aligned and contained in the image, then
+/// reads the contents of \a i_poreAddress into \a o_data, performing
+/// image-to-host endianness conversion if required.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_read_uint64(const void *i_image,
+ const uint64_t i_poreAddress,
+ uint64_t* o_data);
+
+
+/// Set scalar data in an SBE-XIP image
+///
+/// \param[in,out] io_image A pointer to an SBE-XIP image in host memory.
+/// The image is assumed to be consistent with the information contained in
+/// the header regarding the presence of and sizes of all sections. The image
+/// is also required to have been normalized.
+///
+/// \param[in] i_id A pointer to a 0-terminated ASCII string naming the item
+/// to be modified.
+///
+/// \param[in] i_data The new scalar data.
+///
+/// This API searches the SBE-XIP Table of Contents (TOC) for the item named
+/// by \a i_id, updating the image from \a i_data if the item is found, has
+/// a scalar type and can be modified. For this API the scalar types include
+/// 8- 32- and 64-bit integers. Although PORE addresses are considered a
+/// scalar type for sbe_xip_get_scalar(), PORE addresses can not be modified
+/// by this API. The caller is responsible for ensuring that the \a i_data is
+/// of the correct size for the underlying data element in the image.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_set_scalar(void* io_image, const char* i_id, const uint64_t i_data);
+
+
+/// Set an integral element in a vector held in an SBE-XIP image
+///
+/// \param[in] i_image A pointer to an SBE-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections. The image is
+/// also required to have been normalized.
+///
+/// \param[in] i_id A pointer to a 0-terminated ASCII string naming the item
+/// to be updated.
+///
+/// \param[in] i_index The index of the vector element to update.
+///
+/// \param[out] i_data The new vector element.
+///
+/// This API searches the SBE-XIP Table of Contents (TOC) for the \a i_index
+/// element of the item named \a i_id, update the image from \a i_data if the
+/// item is found, is a vector of an integral type, and the \a i_index is in
+/// bounds. The caller is responsible for ensuring that the \a i_data is of
+/// the correct size for the underlying data element in the image.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_set_element(void *i_image,
+ const char* i_id,
+ const uint32_t i_index,
+ const uint64_t i_data);
+
+
+/// Set string data in an SBE-XIP image
+///
+/// \param[in,out] io_image A pointer to an SBE-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections. The image is
+/// also required to have been normalized.
+///
+/// \param[in] i_id A pointer to a 0-terminated ASCII string naming the item
+/// to be modified.
+///
+/// \param[in] i_data A pointer to the new string data.
+///
+/// This API searches the SBE-XIP Table of Contents (TOC) for the item named
+/// \a i_id, which must be a string variable. If found, then the string data
+/// in the image is overwritten with \a i_data. Strings are held 0-terminated
+/// in the image, and the SBE-XIP format does not maintain a record of the
+/// amount of memory allocated for an individual string. If a string is
+/// overwritten by a shorter string then the 'excess' storage is effectively
+/// lost. If the length of \a i_data is longer that the current strlen() of
+/// the string data then \a i_data is silently truncated to the first
+/// strlen(old_string) characters.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_set_string(void *io_image, const char* i_id, const char* i_data);
+
+
+/// Directly write 64-bit data into the image based on a PORE address
+///
+/// \param[in, out] io_image A pointer to an SBE-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections.
+///
+/// \param[in] i_poreAddress A relocatable PORE address contained in the
+/// image, presumably of an 8-byte data area. The \a i_poreAddress is
+/// required to be 8-byte aligned, otherwise the SBE_XIP_ALIGNMENT_ERROR code
+/// is returned.
+///
+/// \param[in] i_data The 64 bit data in host format to be written to \a
+/// i_poreAddress.
+///
+/// This API is provided for applications that need to manipulate SBE-XIP
+/// images in terms of their relocatable PORE addresses. The API checks that
+/// the \a i_poreAddress is properly aligned and contained in the image, then
+/// updates the contents of \a i_poreAddress with \a i_data, performing
+/// host-to-image endianness conversion if required.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_write_uint64(void *io_image,
+ const uint64_t i_poreAddress,
+ const uint64_t i_data);
+
+
+/// Map over an SBE-XIP image Table of Contents
+///
+/// \param[in,out] io_image A pointer to an SBE-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections. The image is
+/// also required to have been normalized.
+///
+/// \param[in] i_fn A pointer to a function to call on each TOC entry. The
+/// function has the prototype:
+///
+/// \code
+/// int (*i_fn)(void* io_image,
+/// const SbeXipItem* i_item,
+/// void* io_arg)
+/// \endcode
+///
+/// \param[in,out] io_arg The private argument of \a i_fn.
+///
+/// This API iterates over each entry of the TOC, calling \a i_fn with
+/// pointers to the image, an SbeXipItem* pointer, and a private argument. The
+/// iteration terminates either when all TOC entries have been mapped, or \a
+/// i_fn returns a non-zero code.
+///
+/// \retval 0 Success; All TOC entries were mapped, including the case that
+/// the .toc section is empty.
+///
+/// \retval non-0 May be either one of the SBE-XIP image error codes (see \ref
+/// sbe_xip_image_errors), or a non-zero code from \a i_fn. Since the standard
+/// SBE_XIP return codes are > 0, application-defined codes should be < 0.
+int
+sbe_xip_map_toc(void* io_image,
+ int (*i_fn)(void* io_image,
+ const SbeXipItem* i_item,
+ void* io_arg),
+ void* io_arg);
+
+
+/// Find an SBE-XIP TOC entry
+///
+/// \param[in] i_image A pointer to an SBE-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections. The image is
+/// also required to have been normalized.
+///
+/// \param[in] i_id A 0-byte terminated ASCII string naming the item to be
+/// searched for.
+///
+/// \param[out] o_item If the search is successful, then the object
+/// pointed to by \a o_item is filled in with the decoded form of the
+/// TOC entry for \a i_id. If the API returns a non-0 error code then the
+/// final state of the storage at \a o_item is undefined. This parameter may
+/// be suppied as 0, in which case sbe_xip_find() serves as a simple predicate
+/// on whether an item is indexded in the TOC.
+///
+/// This API searches the TOC of a normalized SBE-XIP image for the item named
+/// \a i_id, and if found, fills in the structure pointed to by \a
+/// o_item with a decoded form of the TOC entry. If the item is not found,
+/// the following two return codes may be considered non-error codes:
+///
+/// - SBE_XIP_ITEM_NOT_FOUND : No TOC record for \a i_id was found.
+///
+/// - SBE_XIP_DATA_NOT_PRESENT : The item appears in the TOC, however the
+/// section containing the data is no longer present in the image.
+///
+/// If the TOC section has been deleted from the image, then the search is
+/// restricted to the abbreviated TOC that indexes data in the .fixed section.
+/// In this case the \a o_item structure is marked with a 1 in the \a
+/// iv_partial field since the abbreviated TOC can not populate the entire
+/// SbeXipItem structure.
+///
+/// \note This API should typically only be used as a predicate, not as a way
+/// to access the image via the returned SbeXipItem structure. To obtain data
+/// from the image or update data in the image use the sbe_xip_get_*() and
+/// sbe_xip_set_*() APIs respectively.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_find(void* i_image,
+ const char* i_id,
+ SbeXipItem* o_item);
+
+
+/// Map over an SBE-XIP image .halt section
+///
+/// \param[in,out] io_image A pointer to an SBE-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections.
+///
+/// \param[in] i_fn A pointer to a function to call on each entry in .halt.
+/// The function has the prototype:
+///
+/// \code
+/// int (*i_fn)(void* io_image,
+/// const uint64_t i_poreAddress,
+/// const char* i_rcString,
+/// void* io_arg)
+///
+/// \endcode
+///
+/// \param[in,out] io_arg The private argument of \a i_fn.
+///
+/// This API iterates over each entry of the .halt section, calling \a i_fn
+/// with each HALT address, the string form of the return code associated with
+/// that HALT address, and a private argument. The iteration terminates either
+/// when all .halt entries have been mapped, or \a i_fn returns a non-zero
+/// code. The \a i_poreAddddress passed to \a i_fn is the full 48-bit
+/// relocatable PORE address.
+///
+/// \retval 0 Success, including the case that the image has no .halt section.
+///
+/// \retval non-0 May be either one of the SBE-XIP image error codes (see \ref
+/// sbe_xip_image_errors), or any non-zero code from \a i_fn. Since the
+/// standard SBE_XIP return codes are \> 0, application-defined codes should
+/// be \< 0.
+int
+sbe_xip_map_halt(void* io_image,
+ int (*i_fn)(void* io_image,
+ const uint64_t i_poreAddress,
+ const char* i_rcString,
+ void* io_arg),
+ void* io_arg);
+
+
+/// Get the string from of a HALT code from an SBE-XIP image .halt section
+///
+/// \param[in,out] io_image A pointer to an SBE-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections.
+///
+/// \param[in] i_poreAddress This is the 48-bit address found in the PC when
+/// the PORE halts. This address is actually 4 bytes beyond the actual HALT
+/// instruction, however for simplicity this is the address used to index the
+/// HALT.
+///
+/// \param[out] o_rcString The caller provides the address of a string-pointer
+/// variable which is updated with a pointer to the string form of the halt
+/// code associated with \a i_poreAddress (assuming a successful completion).
+///
+/// \retval 0 Success
+///
+/// \revtal SBE_XIP_ITEM_NOT_FOUND The \a i_poreAddress is not associated
+/// with a halt code in .halt.
+///
+/// \revtal Other See \ref sbe_xip_image_errors
+int
+sbe_xip_get_halt(void* io_image,
+ const uint64_t i_poreAddress,
+ const char** o_rcString);
+
+
+/// Delete a section from an SBE-XIP image in host memory
+///
+/// \param[in,out] io_image A pointer to an SBE-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections. The image is
+/// also required to have been normalized.
+///
+/// \param[in] i_sectionId Identifies the section to be deleted. See \ref
+/// sbe_xip_sections.
+///
+/// This API effectively deletes a section from an SBE-XIP image held in host
+/// memory. Unless the requested section \a i_section is already empty, only
+/// the final (highest address offset) section of the image may be deleted.
+/// Deleting the final section of the image means that the section size is set
+/// to 0, and the size of the image recorded in the header is reduced by the
+/// section size. Any alignment padding of the now-last section is also
+/// removed.
+///
+/// \note This API does not check for or warn if other sections in the image
+/// reference the deleted section.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_delete_section(void* io_image, const int i_sectionId);
+
+
+#ifndef PPC_HYP
+
+/// Duplicate a section from an SBE-XIP image in host memory
+///
+/// \param[in,out] i_image A pointer to an SBE-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections.
+///
+/// \param[in] i_sectionId Identifies the section to be duplicated. See \ref
+/// sbe_xip_sections.
+///
+/// \param[out] o_duplicate At exit, points to the newly allocated and
+/// initialized duplicate of the given section. The caller is responsible for
+/// free()-ing this memory when no longer required.
+///
+/// \param[out] o_size At exit, contains the size (in bytes) of the duplicated
+/// section.
+///
+/// This API creates a bytewise duplicate of a non-empty section into newly
+/// malloc()-ed memory. At exit \a o_duplicate points to the duplicate, and \a
+/// o_size is set the the size of the duplicated section. The caller is
+/// responsible for free()-ing the memory when no longer required. The
+/// pointer at \a o_duplicate is set to NULL (0) and the \a o_size is set to 0
+/// in the event of any failure.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_duplicate_section(const void* i_image,
+ const int i_sectionId,
+ void** o_duplicate,
+ uint32_t* o_size);
+
+#endif // PPC_HYP
+
+
+/// Append binary data to an SBE-XIP image held in host memory
+///
+/// \param[in,out] io_image A pointer to an SBE-XIP image in host memory. The
+/// image is assumed to be consistent with the information contained in the
+/// header regarding the presence of and sizes of all sections. The image is
+/// also required to have been normalized.
+///
+/// \param[in] i_sectionId Identifies the section to contain the new data.
+///
+/// \param[in] i_data A pointer to the data to be appended to the image. If
+/// this pointer is NULL (0), then the effect is as if \a i_data were a
+/// pointer to an \a i_size array of 0 bytes.
+///
+/// \param[in] i_size The size of the data to be appended in bytes. If \a
+/// i_data is 0, then this is the number of bytes to clear.
+///
+/// \param[in] i_allocation The size of the memory region containing the
+/// image, measured from the first byte of the image. The call will fail if
+/// appending the new data plus any alignment padding would overflow the
+/// allocated memory.
+///
+/// \param[out] o_sectionOffset If non-0 at entry, then the API updates the
+/// location pointed to by \a o_sectionOffset with the offset of the first
+/// byte of the appended data within the indicated section. This return value
+/// is invalid in the event of a non-0 return code.
+///
+/// This API copies data from \a i_data to the end of the indicated \a
+/// i_section. The section \a i_section must either be empty, or must be the
+/// final (highest address) section in the image. If the section is initially
+/// empty and \a i_size is non-0 then the section is created at the end of the
+/// image. The size of \a i_section and the size of the image are always
+/// adjusted to reflect the newly added data. This is a simple binary copy
+/// without any interpretation (e.g., endian-translation) of the copied data.
+/// The caller is responsible for insuring that the host memory area
+/// containing the SBE-XIP image is large enough to hold the newly appended
+/// data without causing addressing errors or buffer overrun errors.
+///
+/// The final parameter \a o_sectionOffset is optional, and may be passed as
+/// NULL (0) if the application does not require the information. This return
+/// value is provided to simplify typical use cases of this API:
+///
+/// - A scan program is appended to the image, or a run-time data area is
+/// allocated and cleared at the end of the image.
+///
+/// - Pointer variables in the image are updated with PORE addresses obtained
+/// via sbe_xip_section2pore(), or
+/// other procedure code initializes a newly allocated and cleared data area
+/// via host addresses obtained from sbe_xip_section2host().
+///
+/// Regarding alignment, note that the SBE-XIP format requires that sections
+/// maintain an initial alignment that varies by section, and the API will
+/// enforce these alignment constraints for all sections created by the API.
+/// All alignment is relative to the first byte of the image (\a io_image) -
+/// \e not to the current in-memory address of the image. By specification
+/// SBE-XIP images must be loaded at a 4K alignment in order for PORE hardware
+/// relocation to work, however the APIs don't require this 4K alignment for
+/// in-memory manipulation of images. Images to be executed on PoreVe will
+/// normally require at least 8-byte final aligment in order to guarantee that
+/// the PoreVe can execute an 8-byte fetch or load/store of the final
+/// doubleword.
+///
+/// \note If the TOC section is modified then the image is marked as having an
+/// unsorted TOC.
+///
+/// \note If the call fails for any reason (other than a bug in the API
+/// itself) then the \a io_image data is returned unmodified.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_append(void* io_image,
+ const int i_sectionId,
+ const void* i_data,
+ const uint32_t i_size,
+ const uint32_t i_allocation,
+ uint32_t* o_sectionOffset);
+
+
+/// Convert an SBE-XIP section offset to a relocatable PORE address
+///
+/// \param[in] i_image A pointer to an SBE-XIP image in host memory
+///
+/// \param[in] i_sectionId A valid SBE-XIP section identifier; The section
+/// must be non-empty.
+///
+/// \param[in] i_offset An offset (in bytes) within the section. At least one
+/// byte at \a i_offset must be currently allocated in the section.
+///
+/// \param[in] o_poreAddress The equivalent relocatable PORE address is
+/// returned via this pointer. Since valid PORE addresses are always either
+/// 4-byte (code) or 8-byte (data) aligned, this API checks the aligment of
+/// the translated address and returns SBE_XIP_ALIGNMENT_ERROR if the PORE
+/// address is not at least 4-byte aligned. Note that the translated address
+/// is still returned even if incorrectly aligned.
+///
+/// This API is typically used to translate section offsets returned from
+/// sbe_xip_append() into relocatable PORE addresses.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_section2pore(const void* i_image,
+ const int i_sectionId,
+ const uint32_t i_offset,
+ uint64_t* o_poreAddress);
+
+
+/// Convert an SBE-XIP relocatable PORE address to a host memory address
+///
+/// \param[in] i_image A pointer to an SBE-XIP image in host memory.
+///
+/// \param[in] i_poreAddress A relocatable PORE address putatively addressing
+/// relocatable memory contained in the image.
+///
+/// \param[out] o_hostAddress The API updates the location pointed to by \a
+/// o_hostAddress with the host address of the memory addressed by \a
+/// i_poreAddress. In the event of an error (non-0 return code) the final
+/// content of \a o_hostAddress is undefined.
+///
+/// This API is typically used to translate relocatable PORE addresses stored
+/// in the SBE-XIP image into the equivalent host address of the in-memory
+/// image, allowing host-code to manipulate arbitrary data structures in the
+/// image. If the \a i_poreAddress does not refer to memory within the image
+/// (as determined by the link address and image size) then the
+/// SBE_XIP_INVALID_ARGUMENT error code is returned.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_pore2host(const void* i_image,
+ const uint64_t i_poreAddress,
+ void** o_hostAddress);
+
+
+/// Convert an SBE-XIP relocatable PORE address to section Id and offset
+///
+/// \param[in] i_image A pointer to an SBE-XIP image in host memory.
+///
+/// \param[in] i_poreAddress A relocatable PORE address putatively addressing
+/// relocatable memory contained in the image.
+///
+/// \param[out] o_section The API updates the location pointed to by \a
+/// o_section with the section Id of the memory addressed by \a
+/// i_poreAddress. In the event of an error (non-0 return code) the final
+/// content of \a o_section is undefined.
+///
+/// \param[out] o_offset The API updates the location pointed to by \a
+/// o_offset with the byte offset of the memory addressed by \a i_poreAddress
+/// within \a o_section. In the event of an error (non-0 return code) the
+/// final content of \a o_offset is undefined.
+///
+/// This API is typically used to translate relocatable PORE addresses stored
+/// in the SBE-XIP image into the equivalent section + offset form, allowing
+/// host-code to manipulate arbitrary data structures in the image. If the \a
+/// i_poreAddress does not refer to memory within the image (as determined by
+/// the link address and image size) then the SBE_XIP_INVALID_ARGUMENT error
+/// code is returned.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_pore2section(const void* i_image,
+ const uint64_t i_poreAddress,
+ int* o_section,
+ uint32_t* o_offset);
+
+
+/// Convert an in-memory SBE-XIP host address to a relocatable PORE address
+///
+/// \param[in] i_image A pointer to an SBE-XIP image in host memory
+///
+/// \param[in] i_hostAddress A host address addressing data within the image.
+///
+/// \param[out] o_poreAddress The API updates the location pointed to by \a
+/// o_poreAddress with the equivalent relocatable PORE address of the memory
+/// addressed by i_hostAddress. Since valid PORE addresses are always either
+/// 4-byte (code) or 8-byte (data) aligned, this API checks the aligment of
+/// the translated address and returns SBE_XIP_ALIGNMENT_ERROR if the PORE
+/// address is not at least 4-byte aligned. Note that the translated address
+/// is still returned evn if incorrectly aligned.
+///
+/// This API is provided as a convenient way to convert host memory addresses
+/// for an in-memory SBE-XIP image into PORE addresses correctly relocated for
+/// the image, for example to update pointer variables in the image. If the
+/// \a i_hostAddress does not refer to memory within the image (as determined
+/// by the image address and image size) then the SBE_XIP_INVALID_ARGUMENT
+/// error code is returned.
+///
+/// \retval 0 Success
+///
+/// \retval non-0 See \ref sbe_xip_image_errors
+int
+sbe_xip_host2pore(const void* i_image,
+ void* i_hostAddress,
+ uint64_t* o_poreAddress);
+
+
+/// \defgroup sbe_xip_image_errors Error codes from SBE-XIP image APIs
+///
+/// @{
+
+/// A putative SBE-XIP image does not have the correct magic number, or
+/// contains some other major inconsistency.
+#define SBE_XIP_IMAGE_ERROR 1
+
+/// The TOC may be missing, partially present or may have an alignment problem.
+#define SBE_XIP_TOC_ERROR 2
+
+/// A named item was not found in the SBE-XIP TOC, or a putative HALT address
+/// is not associated with a halt code in .halt.
+#define SBE_XIP_ITEM_NOT_FOUND 3
+
+/// A named item appears in the SBE-XIP TOC, but the data is not present in
+/// the image. This error can occur if sections have been deleted from the
+/// image.
+#define SBE_XIP_DATA_NOT_PRESENT 4
+
+/// A named item appears in the SBE-XIP TOC, but the data can not be
+/// modified. This error will occur if an attempt is made to modify an
+/// address-only entry.
+#define SBE_XIP_CANT_MODIFY 5
+
+/// A direct or implied argument is invalid, e.g. an illegal data type or
+/// section identifier, or an address not contained within the image.
+#define SBE_XIP_INVALID_ARGUMENT 6
+
+/// A data type mismatch or an illegal type was specified or implied for an
+/// operation.
+#define SBE_XIP_TYPE_ERROR 7
+
+/// A bug in an SBE-XIP image API
+#define SBE_XIP_BUG 8
+
+/// The image must first be normalized with sbe_xip_normalize().
+#define SBE_XIP_NOT_NORMALIZED 9
+
+/// Attempt to delete a non-empty section that is not the final section of the
+/// image, or an attempt to append data to a non-empty section that is not the
+/// final section of the image, or an attempt to operate on an empty section
+/// for those APIs that prohibit this.
+#define SBE_XIP_SECTION_ERROR 10
+
+/// An address translation API returned a PORE address that was not at least
+/// 4-byte aligned, or alignment violations were observed by
+/// sbe_xip_validate() or sbe_xip_append().
+#define SBE_XIP_ALIGNMENT_ERROR 11
+
+/// An API that performs dynamic memory allocation was unable to allocate
+/// memory.
+#define SBE_XIP_NO_MEMORY 12
+
+/// Attempt to get or set a vector element with an index that is outside of
+/// the declared bounds of the vector.
+#define SBE_XIP_BOUNDS_ERROR 13
+
+/// Attempt to grow the image past its defined memory allocation
+#define SBE_XIP_WOULD_OVERFLOW 14
+
+/// Error associated with the disassembler occurred.
+#define SBE_XIP_DISASSEMBLER_ERROR 15
+
+/// hash collision creating the .fixed_toc section
+#define SBE_XIP_HASH_COLLISION 16
+
+/// Applications can expand this macro to declare an array of string forms of
+/// the error codes if desired.
+#define SBE_XIP_ERROR_STRINGS(var) \
+ const char* var[] = { \
+ "Success", \
+ "SBE_XIP_IMAGE_ERROR", \
+ "SBE_XIP_TOC_ERROR", \
+ "SBE_XIP_ITEM_NOT_FOUND", \
+ "SBE_XIP_DATA_NOT_PRESENT", \
+ "SBE_XIP_CANT_MODIFY", \
+ "SBE_XIP_INVALID_ARGUMENT", \
+ "SBE_XIP_TYPE_ERROR", \
+ "SBE_XIP_BUG", \
+ "SBE_XIP_NOT_NORMALIZED", \
+ "SBE_XIP_SECTION_ERROR", \
+ "SBE_XIP_ALIGNMENT_ERROR", \
+ "SBE_XIP_NO_MEMORY", \
+ "SBE_XIP_BOUNDS_ERROR", \
+ "SBE_XIP_WOULD_OVERFLOW", \
+ "SBE_XIP_DISASSEMBLER_ERROR", \
+ "SBE_XIP_HASH_COLLISION", \
+ }
+
+/// Applications can use this macro to safely index the array of error
+/// strings.
+#define SBE_XIP_ERROR_STRING(var, n) \
+ ((((n) < 0) || ((n) > (int)(sizeof(var) / sizeof(char*)))) ? \
+ "Bug : Invalid SBE-XIP error code" : var[n])
+
+/// @}
+
+/// Disassembler error codes.
+#define DIS_IMAGE_ERROR 1
+#define DIS_MEMORY_ERROR 2
+#define DIS_DISASM_ERROR 3
+#define DIS_RING_NAME_ADDR_MATCH_SUCCESS 4
+#define DIS_RING_NAME_ADDR_MATCH_FAILURE 5
+#define DIS_TOO_MANY_DISASM_WARNINGS 6
+#define DIS_DISASM_TROUBLES 7
+
+#define DIS_ERROR_STRINGS(var) \
+ const char* var[] = { \
+ "Success", \
+ "DIS_IMAGE_ERROR", \
+ "DIS_MEMORY_ERROR", \
+ "DIS_DISASM_ERROR", \
+ "DIS_RING_NAME_ADDR_MATCH_SUCCESS", \
+ "DIS_RING_NAME_ADDR_MATCH_FAILURE", \
+ "DIS_TOO_MANY_DISASM_WARNINGS", \
+ "DIS_DISASM_TROUBLES", \
+ }
+
+#define DIS_ERROR_STRING(var, n) \
+ ((((n) < 0) || ((n) > (int)(sizeof(var) / sizeof(char*)))) ? \
+ "Bug : Invalid DIS error code" : var[n])
+
+#if 0
+{ /* So __cplusplus doesn't mess w/auto-indent */
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __ASSEMBLER__
+
+
+////////////////////////////////////////////////////////////////////////////
+// Assembler Definitions
+////////////////////////////////////////////////////////////////////////////
+
+#ifdef __ASSEMBLER__
+
+/// Create an XIP TOC entry
+///
+/// \param[in] index The string form of the \a index symbol is created and
+/// linked from the TOC entry to allow external search procedures to locate
+/// the \a address.
+///
+/// \param[in] type One of the SBE_XIP_* type constants; See \ref
+/// sbe_xip_toc_types.
+///
+/// \param[in] address The address of the idexed code or data; This wlll
+/// typically be a symbol.
+///
+/// \param[in] elements <Optional> For vector types, number of elements in the
+/// vector, which is limited to an 8-bit unsigned integer. This parameter
+/// defaults to 1 which indicates a scalar type. Declaring a vector with 0
+/// elements disables bounds checking on vector accesses, and can be used if
+/// very large or indeterminate sized vectors are required. The TOC format
+/// does not support vectors of strings or addresses.
+///
+/// The \c .xip_toc macro creates a XIP Table of Contents (TOC) structure in
+/// the \c .toc section, as specified by the parameters. This macro is
+/// typically not used directly in assembly code. Instead programmers should
+/// use .xip_quad, .xip_quada, .xip_quadia, .xip_address, .xip_string or
+/// .xip_cvs_revision.
+
+ .macro .xip_toc, index:req, type:req, address:req, elements=1
+
+ .if (((\type) < 1) || ((\type) > SBE_XIP_MAX_TYPE_INDEX))
+ .error ".xip_toc : Illegal type index"
+ .endif
+
+ // First push into the .strings section to lay down the
+ // string form of the index name under a local label.
+
+ .pushsection .strings
+7667862:
+ .asciz "\index"
+ .popsection
+
+ // Now the 12-byte TOC entry is created. Push into the .toc section
+ // and lay down the first 4 bytes which are always a pointer to the
+ // string just declared. The next 4 bytes are the address of the data
+ // (or the address itself in the case of address types). The final 4
+ // bytes are the type, section (always 0 prior to normalization),
+ // number of elements, and a padding byte.
+
+ .pushsection .toc
+
+ .long 7667862b, (\address)
+ .byte (\type), 0, (\elements), 0
+
+ .popsection
+
+ .endm
+
+
+/// Allocate and initialize 64-bit global scalar or vector data and create the
+/// TOC entry.
+///
+/// \param[in] symbol The name of the scalar or vector; this name is also used
+/// as the TOC index of the data.
+///
+/// \param[in] init The initial value of (each element of) the data.
+/// This is a 64-bit integer; To allocate address pointers use .xip_quada.
+///
+/// \param[in] elements The number of 64-bit elements in the data structure,
+/// defaulting to 1, with a maximum value of 255.
+///
+/// \param[in] section The section where the data will be allocated,
+/// default depends on the memory space
+
+ .macro .xip_quad, symbol:req, init:req, elements=1, section
+
+ ..xip_quad_helper .quad, \symbol, (\init), (\elements), \section
+
+ .endm
+
+
+/// Allocate and initialize 64-bit global scalar or vector data containing a
+/// relocatable address in and create the TOC entry.
+///
+/// \param[in] symbol The name of the scalar or vector; this name is also used
+/// as the TOC index of the data.
+///
+/// \param[in] init The initial value of (each element of) the data. This
+/// will typically be a symbolic address. If the intention is to define an
+/// address that will always be filled in later by image manipulation tools,
+/// then use the .xip_quad macro with a 0 initial value.
+///
+/// \param[in] elements The number of 64-bit elements in the data structure,
+/// defaulting to 1, with a maximum value of 255.
+///
+/// \param[in] section The section where the data will be allocated,
+/// default depends on the memory space
+
+ .macro .xip_quada, symbol:req, offset:req, elements=1, section
+
+ ..xip_quad_helper .quada, \symbol, (\offset), (\elements), \section
+
+ .endm
+
+
+/// Helper for .xip_quad and .xip_quada
+
+ .macro ..xip_quad_helper, directive, symbol, init, elements, section
+
+ .if (((\elements) < 1) || ((\elements) > 255))
+ .error "The number of vector elements must be in the range 1..255"
+ .endif
+
+ ..xip_pushsection \section
+ .balign 8
+
+ .global \symbol
+\symbol\():
+ .rept (\elements)
+ \directive (\init)
+ .endr
+
+ .popsection
+
+ .xip_toc \symbol, SBE_XIP_UINT64, \symbol, (\elements)
+
+ .endm
+
+
+/// Allocate and initialize 64-bit global scalar or vector data containing
+/// full 64-bit addresses and create a TOC entry
+///
+/// \param[in] symbol The name of the scalar or vector; this name is also used
+/// as the TOC index of the data.
+///
+/// \param[in] space A valid PORE memory space descriptor
+///
+/// \param[in] offset A 32-bit relocatable offset
+///
+/// \param[in] elements The number of 64-bit elements in the data structure,
+/// defaulting to 1, with a maximum value of 255.
+///
+/// \param[in] section The section where the data will be allocated,
+/// default depends on the memory space
+
+ .macro .xip_quadia, symbol:req, space:req, offset:req, \
+ elements=1, section
+
+ .if (((\elements) < 1) || ((\elements) > 255))
+ .error "The number of vector elements must be in the range 1..255"
+ .endif
+
+ ..xip_pushsection \section
+ .balign 8
+
+ .global \symbol
+\symbol\():
+ .rept (\elements)
+ .quadia (\space), (\offset)
+ .endr
+
+ .popsection
+
+ .xip_toc \symbol, SBE_XIP_UINT64, \symbol, (\elements)
+
+ .endm
+
+/// Default push into .ipl_data unless in an OCI space, then .data
+
+ .macro ..xip_pushsection, section
+
+ .ifnb \section
+ .pushsection \section
+ .else
+ .if (_PGAS_DEFAULT_SPACE == PORE_SPACE_OCI)
+ .pushsection .data
+ .else
+ .pushsection .ipl_data
+ .endif
+ .endif
+
+ .balign 8
+
+ .endm
+
+/// Allocate and initialize a string in .strings
+///
+/// \param[in] index The string will be stored in the TOC using this index
+/// symbol.
+///
+/// \param[in] string The string to be allocated in .strings. String space is
+/// fixed once allocated. Strings designed to be overwritten by external tools
+/// should be allocated to be as long as eventually needed (e.g., by a string
+/// of blanks.)
+
+ .macro .xip_string, index:req, string:req
+
+ .pushsection .strings
+7874647:
+ .asciz "\string"
+ .popsection
+
+ .xip_toc \index, SBE_XIP_STRING, 7874647b
+
+ .endm
+
+
+/// Allocate and initialize a CVS Revison string in .strings
+///
+/// \param[in] index The string will be stored in the TOC using this index
+/// symbol.
+///
+/// \param[in] string A CVS revision string to be allocated in .strings. CVS
+/// revision strings are formatted by stripping out and only storing the
+/// actual revision number :
+///
+/// \code
+/// "$Revision <n>.<m> $" -> "<n>.<m>"
+/// \endcode
+
+
+ .macro .xip_cvs_revision, index:req, string:req
+
+ .pushsection .strings
+7874647:
+ ..cvs_revision_string "\string"
+ .popsection
+
+ .xip_toc \index, SBE_XIP_STRING, 7874647b
+
+ .endm
+
+
+/// Shorthand to create a TOC entry for an address
+///
+/// \param[in] index The symbol will be indexed as this name
+///
+/// \param[in] symbol <Optional> The symbol to index; by default the same as
+/// the index.
+
+ .macro .xip_address, index:req, symbol
+
+ .ifb \symbol
+ .xip_toc \index, SBE_XIP_ADDRESS, \index
+ .else
+ .xip_toc \index, SBE_XIP_ADDRESS, \symbol
+ .endif
+
+ .endm
+
+
+/// Edit and allocate a CVS revision string
+///
+/// CVS revision strings are formatted by stripping out and only storing the
+/// actual revision number :
+/// \code
+/// "$Revision <n>.<m> $" -> "<n>.<m>"
+/// \endcode
+
+ .macro ..cvs_revision_string, rev:req
+ .irpc c, \rev
+ .ifnc "\c", "$"
+ .ifnc "\c", "R"
+ .ifnc "\c", "e"
+ .ifnc "\c", "v"
+ .ifnc "\c", "i"
+ .ifnc "\c", "s"
+ .ifnc "\c", "i"
+ .ifnc "\c", "o"
+ .ifnc "\c", "n"
+ .ifnc "\c", ":"
+ .ifnc "\c", " "
+ .ascii "\c"
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endr
+ .byte 0
+ .endm
+
+#endif // __ASSEMBLER__
+
+#endif // __SBE_XIP_TOC_H