[Skiboot] [PATCH 2/2] STOP API: Changes for SMF and SPR self save

Akshay Adiga akshay.adiga at linux.vnet.ibm.com
Tue Oct 16 18:45:06 AEDT 2018


From: Prem Shanker Jha <premjha2 at in.ibm.com>

    Commit accomplishes following:
        -   Implementation of new self restore region memory layout
        -   Restore of SPRs pertaining to SMF
        -   Self save of SPRs
        -   Backward compatibility with old self restore layout
Key_Cronus_Test=PM_REGRESS

Change-Id: I11359e392102d32896251225907eb95a43ba6f78
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/66212
Reviewed-by: RANGANATHPRASAD G. BRAHMASAMUDRA <prasadbgr at in.ibm.com>
Tested-by: Jenkins Server <pfd-jenkins+hostboot at us.ibm.com>
Tested-by: HWSV CI <hwsv-ci+hostboot at us.ibm.com>
Tested-by: Cronus HW CI <cronushw-ci+hostboot at us.ibm.com>
Tested-by: Hostboot CI <hostboot-ci+hostboot at us.ibm.com>
Reviewed-by: Gregory S. Still <stillgs at us.ibm.com>
Reviewed-by: Jennifer A. Stofer <stofer at us.ibm.com>
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/66216
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot at us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot at us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot at us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell at us.ibm.com>
Signed-off-by: Akshay Adiga <akshay.adiga at linux.vnet.ibm.com>
---
 libpore/p9_cpu_reg_restore_instruction.H |  43 +-
 libpore/p9_hcd_memmap_base.H             |  30 +-
 libpore/p9_stop_api.C                    | 723 +++++++++++++++++++++--
 libpore/p9_stop_api.H                    | 136 ++++-
 libpore/p9_stop_data_struct.H            |  65 +-
 libpore/p9_stop_util.C                   |   3 +-
 6 files changed, 886 insertions(+), 114 deletions(-)

diff --git a/libpore/p9_cpu_reg_restore_instruction.H b/libpore/p9_cpu_reg_restore_instruction.H
index e5689ae8..dd4358a8 100644
--- a/libpore/p9_cpu_reg_restore_instruction.H
+++ b/libpore/p9_cpu_reg_restore_instruction.H
@@ -5,7 +5,7 @@
 /*                                                                        */
 /* OpenPOWER HostBoot Project                                             */
 /*                                                                        */
-/* Contributors Listed Below - COPYRIGHT 2015,2017                        */
+/* Contributors Listed Below - COPYRIGHT 2015,2018                        */
 /* [+] International Business Machines Corp.                              */
 /*                                                                        */
 /*                                                                        */
@@ -50,21 +50,32 @@ namespace stopImageSection
  */
 enum
 {
-    ORI_OPCODE        = 24,
-    RFI_OPCODE        = 19,
-    RFI_CONST         = 50,
-    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
-    BLR_INST          = 0x4e800020,
-    MTSPR_BASE_OPCODE = 0x7c0003a6,
-    ATTN_OPCODE       = 0x00000200,
+    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,
+    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
diff --git a/libpore/p9_hcd_memmap_base.H b/libpore/p9_hcd_memmap_base.H
index e579eea9..000fafef 100644
--- a/libpore/p9_hcd_memmap_base.H
+++ b/libpore/p9_hcd_memmap_base.H
@@ -56,7 +56,7 @@ HCD_CONST64(PPMR_MAGIC_NUMBER,                  ULL(0x50504d525f312e30))  // PPM
 HCD_CONST64(PGPE_MAGIC_NUMBER,                  ULL(0x504750455F312E30))  // PGPE_1.0
 
 HCD_CONST(CME_BUILD_VERSION,                    0x001) // CME__1.0
-HCD_CONST(SGPE_BUILD_VERSION,                   0x002) // SGPE_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
@@ -278,8 +278,7 @@ HCD_CONST(MAX_L3_SCOM_ENTRIES,                  16)
 // Reserve                  06
 
 HCD_CONST(MAX_EQ_SCOM_ENTRIES,                  31)
-HCD_CONST(QUAD_SCOM_RESTORE_REGS_PER_QUAD,
-          (MAX_EQ_SCOM_ENTRIES + MAX_L2_SCOM_ENTRIES + MAX_L3_SCOM_ENTRIES + 1))
+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))
@@ -298,6 +297,9 @@ 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)
@@ -312,7 +314,7 @@ 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
+/// Self Restore without SMF Support
 
 HCD_CONST(SELF_RESTORE_CPMR_OFFSET,             CPMR_HEADER_SIZE)
 HCD_CONST(SELF_RESTORE_INT_SIZE,                (8 * ONE_KB))
@@ -331,7 +333,25 @@ HCD_CONST(SELF_RESTORE_CORE_REGS_SIZE,
 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))
diff --git a/libpore/p9_stop_api.C b/libpore/p9_stop_api.C
index 03d9ff99..33aaf788 100644
--- a/libpore/p9_stop_api.C
+++ b/libpore/p9_stop_api.C
@@ -37,16 +37,12 @@
 #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 __FAPI_2_
-    #include <fapi2.H>
-#endif
-
 #ifdef __cplusplus
 extern "C" {
 
@@ -58,24 +54,80 @@ namespace stopImageSection
 
 const StopSprReg_t g_sprRegister[] =
 {
-    { P9_STOP_SPR_HSPRG0,    true  },
-    { P9_STOP_SPR_HRMOR,     false },
-    { P9_STOP_SPR_LPCR,      true  },
-    { P9_STOP_SPR_HMEER,     false },
-    { P9_STOP_SPR_LDBAR,     true  },
-    { P9_STOP_SPR_PSSCR,     true  },
-    { P9_STOP_SPR_PMCR,      false },
-    { P9_STOP_SPR_HID,       false },
-    { P9_STOP_SPR_MSR,       true  },
-    { P9_STOP_SPR_DAWR,      true  },
+    { 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 =  10;
+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.
@@ -141,11 +193,11 @@ STATIC StopReturnCode_t validateSprImageInputs( void*   const i_pImage,
 
         for( index = 0; index < MAX_SPR_SUPPORTED; ++index )
         {
-            if( i_regId == (CpuReg_t )g_sprRegister[index].sprId )
+            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].isThreadScope;
+                *i_pThreadLevelReg = g_sprRegister[index].iv_isThreadScope;
                 *i_pThreadId = *i_pThreadLevelReg ? *i_pThreadId : 0;
                 break;
             }
@@ -271,6 +323,20 @@ STATIC uint32_t getMtsprInstruction( const uint16_t i_Rs, const uint16_t i_Spr )
 
 //-----------------------------------------------------------------------------
 
+/**
+ * @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
@@ -283,7 +349,6 @@ 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 = 0;
     rldicrInstOpcode = ((RLDICR_OPCODE << 26 ) | ( i_Rs << 21 ) | ( i_Ra << 16 ));
     rldicrInstOpcode |= ( ( i_sh & 0x001F ) << 11 ) | (RLDICR_CONST << 2 );
     rldicrInstOpcode |= (( i_sh & 0x0020 ) >> 4);
@@ -294,6 +359,24 @@ STATIC uint32_t getRldicrInstruction( const uint16_t i_Ra, const uint16_t i_Rs,
 
 //-----------------------------------------------------------------------------
 
+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.
@@ -305,25 +388,39 @@ STATIC uint32_t getRldicrInstruction( const uint16_t i_Ra, const uint16_t i_Rs,
  * @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 )
+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);
-    uint32_t temp               =   i_isThreadReg ? (uint32_t)(CORE_RESTORE_THREAD_AREA_SIZE) :
-                                    (uint32_t)(CORE_RESTORE_CORE_AREA_SIZE);
-    uint32_t* i_threadSectEnd   =   i_pThreadSectLoc + ( temp >> 2 );
     *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 ) &&
@@ -340,7 +437,6 @@ STATIC StopReturnCode_t lookUpSprInImage( uint32_t* i_pThreadSectLoc,
 
             i_pThreadSectLoc = i_pThreadSectLoc + SIZE_PER_SPR_RESTORE_INST;
         }
-
     }
     while(0);
 
@@ -358,7 +454,9 @@ STATIC StopReturnCode_t lookUpSprInImage( uint32_t* i_pThreadSectLoc,
  */
 STATIC StopReturnCode_t updateSprEntryInImage( uint32_t* i_pSprEntryLocation,
         const CpuReg_t i_regId,
-        const uint64_t i_regData )
+        const uint64_t i_regData,
+        const enum SprEntryUpdateMode i_mode
+                                             )
 {
     StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
     uint32_t tempInst       =   0;
@@ -387,9 +485,19 @@ STATIC StopReturnCode_t updateSprEntryInImage( uint32_t* i_pSprEntryLocation,
         *i_pSprEntryLocation = tempInst;
         i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
 
-        //clear R0 i.e. "xor ra, rs, rb"
-        tempInst = getXorInstruction( regRs, regRs, regRs );
-        *i_pSprEntryLocation = tempInst;
+        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;
@@ -432,15 +540,22 @@ STATIC StopReturnCode_t updateSprEntryInImage( uint32_t* i_pSprEntryLocation,
             //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 )
+        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 );
         }
@@ -463,22 +578,89 @@ STATIC StopReturnCode_t updateSprEntryInImage( uint32_t* i_pSprEntryLocation,
 
 //-----------------------------------------------------------------------------
 
+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;
+    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;
+        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" );
 
@@ -510,17 +692,38 @@ StopReturnCode_t p9_stop_save_cpureg(  void* const i_pImage,
             break;
         }
 
-        chipHomer = ( HomerSection_t*)i_pImage;
+        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( threadScopeReg )
+        if( l_selfRestVer )
         {
-            pThreadLocation =
-                &(chipHomer->coreThreadRestore[coreId][threadId].threadArea[0]);
+            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
+        else    //Old fips or OPAL release that doesn't support SMF
         {
-            pThreadLocation =
-                &(chipHomer->coreThreadRestore[coreId][threadId].coreArea[0]);
+            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 ) ||
@@ -537,7 +740,8 @@ StopReturnCode_t p9_stop_save_cpureg(  void* const i_pImage,
             l_rc = lookUpSprInImage( (uint32_t*)pThreadLocation,
                                      lookUpKey,
                                      threadScopeReg,
-                                     &pSprEntryLocation );
+                                     &pSprEntryLocation,
+                                     l_selfRestVer );
         }
 
         if( l_rc )
@@ -548,9 +752,19 @@ StopReturnCode_t p9_stop_save_cpureg(  void* const i_pImage,
             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,
-                                      i_regData );
+                                      l_sprValue,
+                                      UPDATE_SPR_ENTRY );
 
         if( l_rc )
         {
@@ -1108,6 +1322,419 @@ StopReturnCode_t p9_stop_save_scom( void* const   i_pImage,
     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
diff --git a/libpore/p9_stop_api.H b/libpore/p9_stop_api.H
index 6416771d..17caedb3 100644
--- a/libpore/p9_stop_api.H
+++ b/libpore/p9_stop_api.H
@@ -5,7 +5,7 @@
 /*                                                                        */
 /* OpenPOWER HostBoot Project                                             */
 /*                                                                        */
-/* Contributors Listed Below - COPYRIGHT 2015,2017                        */
+/* Contributors Listed Below - COPYRIGHT 2015,2018                        */
 /* [+] International Business Machines Corp.                              */
 /*                                                                        */
 /*                                                                        */
@@ -54,10 +54,17 @@ namespace stopImageSection
 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
@@ -70,21 +77,23 @@ typedef enum
  */
 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_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;
 
 /**
@@ -92,16 +101,16 @@ typedef enum
  */
 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
+    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;
 
 /**
@@ -109,12 +118,12 @@ typedef enum
  */
 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
+    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;
 
 /**
@@ -126,6 +135,31 @@ typedef enum
     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
@@ -143,6 +177,18 @@ 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
@@ -164,6 +210,32 @@ StopReturnCode_t p9_stop_save_scom( void* const   i_pImage,
                                     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
diff --git a/libpore/p9_stop_data_struct.H b/libpore/p9_stop_data_struct.H
index 940f4057..1e9721e0 100644
--- a/libpore/p9_stop_data_struct.H
+++ b/libpore/p9_stop_data_struct.H
@@ -63,8 +63,21 @@ namespace stopImageSection
 
 enum
 {
-    MAX_SPR_RESTORE_INST = 0x08,
-    SIZE_PER_SPR_RESTORE_INST = ((4 * sizeof(uint8_t)) / sizeof(uint32_t)),
+    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
@@ -79,8 +92,16 @@ typedef struct
  */
 typedef struct
 {
-    uint8_t threadArea[CORE_RESTORE_THREAD_AREA_SIZE];
-    uint8_t coreArea[CORE_RESTORE_CORE_AREA_SIZE];
+    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;
 
 /**
@@ -90,13 +111,28 @@ typedef struct
  */
 typedef struct
 {
-    uint8_t occ_host_sgpe_area[ TWO_MB ];  // CPU restore area starts at an offset of 2MB from chip HOMER
-    uint8_t interrruptHandler[SELF_RESTORE_INT_SIZE];
-    uint8_t threadLauncher[THREAD_LAUNCHER_SIZE];
-    SprRestoreArea_t coreThreadRestore[MAX_CORES_PER_CHIP][MAX_THREADS_PER_CORE];
+    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,
@@ -116,14 +152,19 @@ typedef struct
  */
 typedef struct
 {
-    uint32_t sprId;
-    bool isThreadScope;
+    uint32_t iv_sprId;
+    bool     iv_isThreadScope;
+    uint32_t iv_saveMaskPos;
+
 } StopSprReg_t;
 
 enum
 {
-    SIZE_SCOM_ENTRY = sizeof( ScomEntry_t ),
-    SCOM_ENTRY_START = 0xDEADDEAD,
+    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_
diff --git a/libpore/p9_stop_util.C b/libpore/p9_stop_util.C
index 979455a2..95019884 100644
--- a/libpore/p9_stop_util.C
+++ b/libpore/p9_stop_util.C
@@ -62,7 +62,7 @@ STATIC StopReturnCode_t  isFusedMode( void* const i_pImage, bool* o_fusedMode )
     do
     {
         HomerSection_t* pHomerDesc  =   ( HomerSection_t* ) i_pImage;
-        HomerImgDesc_t* pHomer      =   (HomerImgDesc_t*)( pHomerDesc->interrruptHandler );
+        HomerImgDesc_t* pHomer      =   (HomerImgDesc_t*)( pHomerDesc->iv_interrruptHandler );
 
         if( !i_pImage )
         {
@@ -177,6 +177,7 @@ StopReturnCode_t getCoreAndThread( void* const i_pImage, const uint64_t i_pir,
             }
         }
 
+
         MY_INF("Core Type %s", fusedMode ? "Fused" : "Un-Fused" );
         //quad field is not affected by fuse mode
         *o_pCoreId += 4 * (( coreThreadInfo & 0x70 ) >> 4 );
-- 
2.17.1



More information about the Skiboot mailing list