1 /* IBM_PROLOG_BEGIN_TAG                                                   */
2 /* This is an automatically generated prolog.                             */
3 /*                                                                        */
4 /* $Source: src/import/chips/p9/procedures/utils/stopreg/p9_stop_api.C $  */
5 /*                                                                        */
6 /* OpenPOWER HostBoot Project                                             */
7 /*                                                                        */
8 /* Contributors Listed Below - COPYRIGHT 2015,2018                        */
9 /* [+] International Business Machines Corp.                              */
10 /*                                                                        */
11 /*                                                                        */
12 /* Licensed under the Apache License, Version 2.0 (the "License");        */
13 /* you may not use this file except in compliance with the License.       */
14 /* You may obtain a copy of the License at                                */
15 /*                                                                        */
16 /*     http://www.apache.org/licenses/LICENSE-2.0                         */
17 /*                                                                        */
18 /* Unless required by applicable law or agreed to in writing, software    */
19 /* distributed under the License is distributed on an "AS IS" BASIS,      */
20 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
21 /* implied. See the License for the specific language governing           */
22 /* permissions and limitations under the License.                         */
23 /*                                                                        */
24 /* IBM_PROLOG_END_TAG                                                     */
25 
26 ///
27 /// @file   p9_stop_api.C
28 /// @brief  implements STOP API which  create/manipulate STOP image.
29 ///
30 // *HWP HW Owner    :  Greg Still <stillgs@us.ibm.com>
31 // *HWP FW Owner    :  Prem Shanker Jha <premjha2@in.ibm.com>
32 // *HWP Team        :  PM
33 // *HWP Level       :  2
34 // *HWP Consumed by :  HB:HYP
35 
36 // *INDENT-OFF*
37 #ifdef PPC_HYP
38     #include <HvPlicModule.H>
39 #endif
40 
41 #include "p9_stop_api.H"
42 #include "p9_cpu_reg_restore_instruction.H"
43 #include "p9_stop_data_struct.H"
44 #include <string.h>
45 #include "p9_stop_util.H"
46 #ifdef __cplusplus
47 extern "C" {
48 
49 namespace stopImageSection
50 {
51 #endif
52 // a true in the table below means register is of scope thread
53 // whereas a false meanse register is of scope core.
54 
55 const StopSprReg_t g_sprRegister[] =
56 {
57     { P9_STOP_SPR_CIABR,     true,  0  },
58     { P9_STOP_SPR_DAWR,      true,  1  },
59     { P9_STOP_SPR_DAWRX,     true,  2  },
60     { P9_STOP_SPR_HSPRG0,    true,  3  },
61     { P9_STOP_SPR_LDBAR,     true,  4, },
62     { P9_STOP_SPR_LPCR,      true,  5  },
63     { P9_STOP_SPR_PSSCR,     true,  6  },
64     { P9_STOP_SPR_MSR,       true,  7  },
65     { P9_STOP_SPR_HRMOR,     false, 20 },
66     { P9_STOP_SPR_HID,       false, 21 },
67     { P9_STOP_SPR_HMEER,     false, 22 },
68     { P9_STOP_SPR_PMCR,      false, 23 },
69     { P9_STOP_SPR_PTCR,      false, 24 },
70     { P9_STOP_SPR_SMFCTRL,   true,  28 },
71     { P9_STOP_SPR_USPRG0,    true,  29 },
72     { P9_STOP_SPR_USPRG1,    true,  30 },
73     { P9_STOP_SPR_URMOR,     false, 31 },
74 };
75 
76 const uint32_t MAX_SPR_SUPPORTED =  17;
77 const uint32_t LEGACY_CORE_SCOM_SUPPORTED   =   15;
78 const uint32_t LEGACY_QUAD_SCOM_SUPPORTED   =   63;
79 
80 //-----------------------------------------------------------------------------
81 
82 /**
83  * @brief       vaildated input arguments passed to p9_stop_save_cpureg_control.
84  * @param[in]   i_pImage            point to start of HOMER
85  * @param[in]   i_coreId            id of the core
86  * @param[in]   i_threadId          id of the thread
87  * @param[in]   i_saveMaskVector    SPR save bit mask vector
88  * @return      STOP_SAVE_SUCCESS if function succeeds, error code otherwise.
89  */
validateArgumentSaveRegMask(void * const i_pImage,uint32_t const i_coreId,uint32_t const i_threadId,uint64_t i_saveMaskVector)90 STATIC StopReturnCode_t validateArgumentSaveRegMask( void* const i_pImage,
91         uint32_t const i_coreId,
92         uint32_t const i_threadId,
93         uint64_t i_saveMaskVector )
94 {
95     StopReturnCode_t l_rc   =   STOP_SAVE_SUCCESS;
96 
97     do
98     {
99         if( !i_pImage )
100         {
101             l_rc    =   STOP_SAVE_ARG_INVALID_IMG;
102             break;
103         }
104 
105         if( i_coreId > MAX_CORE_ID_SUPPORTED )
106         {
107             l_rc    =   STOP_SAVE_ARG_INVALID_CORE;
108             break;
109         }
110 
111         if( i_threadId > MAX_THREAD_ID_SUPPORTED )
112         {
113             l_rc    =   STOP_SAVE_ARG_INVALID_THREAD;
114             break;
115         }
116 
117         if( ( 0 == i_saveMaskVector ) || ( BAD_SAVE_MASK & i_saveMaskVector ) )
118         {
119             l_rc    =  STOP_SAVE_ARG_INVALID_REG;
120             break;
121         }
122 
123     }
124     while(0);
125 
126     return l_rc;
127 }
128 
129 //-----------------------------------------------------------------------------
130 
131 /**
132  * @brief   validates input arguments provided by STOP API caller.
133  * @param[in]       i_pImage    pointer to beginning of chip's HOMER image.
134  * @param[in]       i_regId             SPR register id
135  * @param[in]       i_coreId            core id
136  * @param[in|out]   i_pThreadId         points to thread id
137  * @param[in|out]   i_pThreadLevelReg   points to scope information of SPR
138  * @return  STOP_SAVE_SUCCESS if arguments found valid, error code otherwise.
139  * @note    for register of scope core, function shall force io_threadId to
140  *          zero.
141  */
validateSprImageInputs(void * const i_pImage,const CpuReg_t i_regId,const uint32_t i_coreId,uint32_t * i_pThreadId,bool * i_pThreadLevelReg)142 STATIC StopReturnCode_t validateSprImageInputs( void*   const i_pImage,
143         const CpuReg_t i_regId,
144         const uint32_t  i_coreId,
145         uint32_t*     i_pThreadId,
146         bool* i_pThreadLevelReg )
147 {
148     uint32_t index = 0;
149     StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
150     bool sprSupported = false;
151     *i_pThreadLevelReg = false;
152 
153     do
154     {
155         if( NULL == i_pImage )
156         {
157             // Error: HOMER image start location is not valid
158             // Cannot proceed further. So, let us exit.
159             l_rc = STOP_SAVE_ARG_INVALID_IMG;
160             MY_ERR( "invalid image location " );
161 
162             break;
163         }
164 
165         // STOP API manages STOP image based on physical core Id. PIR value
166         // is interpreted to calculate the physical core number and virtual
167         // thread number.
168         if( MAX_CORE_ID_SUPPORTED < i_coreId )
169         {
170             // Error: invalid core number. given core number exceeds maximum
171             // cores supported by chip.
172 
173             // Physical core number is calculated based on following formula:
174             // core id = 4 * quad id (0..5) + core no within quad ( 0..3)
175             l_rc = STOP_SAVE_ARG_INVALID_CORE;
176             MY_ERR( "invalid core id " );
177             break;
178         }
179 
180         if( MAX_THREAD_ID_SUPPORTED < *i_pThreadId )
181         {
182             //Error: invalid core thread. Given core thread exceeds maximum
183             //threads supported in a core.
184 
185             // 64 bit PIR value is interpreted to calculate virtual thread
186             // Id. In fuse mode, b61 and b62 gives virtual thread id whereas in
187             // non fuse mode, b62 and b63 is read to determine the same.
188 
189             l_rc = STOP_SAVE_ARG_INVALID_THREAD;
190             MY_ERR( "invalid thread " );
191             break;
192         }
193 
194         for( index = 0; index < MAX_SPR_SUPPORTED; ++index )
195         {
196             if( i_regId == (CpuReg_t )g_sprRegister[index].iv_sprId )
197             {
198                 // given register is in the list of register supported
199                 sprSupported = true;
200                 *i_pThreadLevelReg = g_sprRegister[index].iv_isThreadScope;
201                 *i_pThreadId = *i_pThreadLevelReg ? *i_pThreadId : 0;
202                 break;
203             }
204         }
205 
206         if( !sprSupported )
207         {
208             // Following SPRs are supported
209             // trace out all registers supported
210             MY_ERR("Register not supported" );
211             // error code to caller.
212             l_rc = STOP_SAVE_ARG_INVALID_REG;
213             break;
214         }
215 
216     }
217     while(0);
218 
219     if( l_rc )
220     {
221         MY_ERR( "image 0x%08x, regId %08d, coreId %d, "
222                 "threadId %d return code 0x%08x", i_pImage, i_regId,
223                 i_coreId, *i_pThreadId, l_rc  );
224     }
225 
226     return l_rc;
227 }
228 
229 //-----------------------------------------------------------------------------
230 
231 /**
232  * @brief generates ori instruction code.
233  * @param[in]   i_Rs    Source register number
234  * @param[in]   i_Ra    destination register number
235  * @param[in]   i_data  16 bit immediate data
236  * @return  returns 32 bit number representing ori instruction.
237  */
getOriInstruction(const uint16_t i_Rs,const uint16_t i_Ra,const uint16_t i_data)238 STATIC uint32_t getOriInstruction( const uint16_t i_Rs, const uint16_t i_Ra,
239                                    const uint16_t i_data )
240 {
241     uint32_t oriInstOpcode = 0;
242     oriInstOpcode = 0;
243     oriInstOpcode = ORI_OPCODE << 26;
244     oriInstOpcode |= i_Rs << 21;
245     oriInstOpcode |= i_Ra << 16;
246     oriInstOpcode |= i_data;
247 
248     return SWIZZLE_4_BYTE(oriInstOpcode);
249 }
250 
251 //-----------------------------------------------------------------------------
252 
253 /**
254  * @brief generates 32 bit key used for SPR lookup in core section.
255  */
genKeyForSprLookup(const CpuReg_t i_regId)256 STATIC uint32_t genKeyForSprLookup( const CpuReg_t i_regId )
257 {
258     return getOriInstruction( 0, 0, (uint16_t) i_regId );
259 }
260 
261 //-----------------------------------------------------------------------------
262 
263 /**
264  * @brief generates xor instruction code.
265  * @param[in] i_Rs  source register number for xor operation
266  * @param[in] i_Ra  destination register number for xor operation result
267  * @param[in] i_Rb source register number for xor operation
268  * @return returns 32 bit number representing xor  immediate instruction.
269  */
getXorInstruction(const uint16_t i_Ra,const uint16_t i_Rs,const uint16_t i_Rb)270 STATIC uint32_t getXorInstruction( const uint16_t i_Ra, const uint16_t i_Rs,
271                                    const uint16_t i_Rb )
272 {
273     uint32_t xorRegInstOpcode;
274     xorRegInstOpcode = XOR_CONST << 1;
275     xorRegInstOpcode |= OPCODE_31 << 26;
276     xorRegInstOpcode |= i_Rs << 21;
277     xorRegInstOpcode |= i_Ra << 16;
278     xorRegInstOpcode |= i_Rb << 11;
279 
280     return SWIZZLE_4_BYTE(xorRegInstOpcode);
281 }
282 
283 //-----------------------------------------------------------------------------
284 
285 /**
286  * @brief generates oris instruction code.
287  * @param[in] i_Rs      source register number
288  * @param[in] i_Ra      destination register number
289  * @param[in] i_data    16 bit immediate data
290  * @return returns 32 bit number representing oris  immediate instruction.
291  */
getOrisInstruction(const uint16_t i_Rs,const uint16_t i_Ra,const uint16_t i_data)292 STATIC uint32_t getOrisInstruction( const uint16_t i_Rs, const uint16_t i_Ra,
293                                     const uint16_t i_data )
294 {
295     uint32_t orisInstOpcode;
296     orisInstOpcode = 0;
297     orisInstOpcode = ORIS_OPCODE << 26;
298     orisInstOpcode |= ( i_Rs & 0x001F ) << 21 | ( i_Ra & 0x001F ) << 16;
299     orisInstOpcode |= i_data;
300 
301     return SWIZZLE_4_BYTE(orisInstOpcode);
302 }
303 
304 //-----------------------------------------------------------------------------
305 
306 /**
307  * @brief generates instruction for mtspr
308  * @param[in] i_Rs      source register number
309  * @param[in] i_Spr represents spr where data is to be moved.
310  * @return returns 32 bit number representing mtspr instruction.
311  */
getMtsprInstruction(const uint16_t i_Rs,const uint16_t i_Spr)312 STATIC uint32_t getMtsprInstruction( const uint16_t i_Rs, const uint16_t i_Spr )
313 {
314     uint32_t mtsprInstOpcode = 0;
315     uint32_t temp = (( i_Spr & 0x03FF ) << 11);
316     mtsprInstOpcode = (uint8_t)i_Rs << 21;
317     mtsprInstOpcode |= ( temp  & 0x0000F800 ) << 5;
318     mtsprInstOpcode |= ( temp & 0x001F0000 ) >> 5;
319     mtsprInstOpcode |= MTSPR_BASE_OPCODE;
320 
321     return SWIZZLE_4_BYTE(mtsprInstOpcode);
322 }
323 
324 //-----------------------------------------------------------------------------
325 
326 /**
327  * @brief generates instruction for mfmsr
328  * @param[in]   i_Rt    target register for SPR content.
329  * @return  returns 32 bit number representing mfmsr instruction.
330  */
getMfmsrInstruction(const uint16_t i_Rt)331 STATIC uint32_t getMfmsrInstruction( const uint16_t i_Rt )
332 {
333     uint32_t mfmsrInstOpcode  = ((OPCODE_31 << 26) | (i_Rt << 21) | (MFMSR_CONST));
334 
335     return SWIZZLE_4_BYTE(mfmsrInstOpcode);
336 }
337 
338 //-----------------------------------------------------------------------------
339 
340 /**
341  * @brief generates rldicr instruction.
342  * @param[in] i_Rs      source register number
343  * @param[in] i_Ra      destination register number
344  * @param[in] i_sh      bit position by which contents of i_Rs are to be shifted
345  * @param[in] i_me      bit position up to which mask should be 1.
346  * @return returns 32 bit number representing rldicr instruction.
347  */
getRldicrInstruction(const uint16_t i_Ra,const uint16_t i_Rs,const uint16_t i_sh,uint16_t i_me)348 STATIC uint32_t getRldicrInstruction( const uint16_t i_Ra, const uint16_t i_Rs,
349                                       const uint16_t i_sh, uint16_t i_me )
350 {
351     uint32_t rldicrInstOpcode = 0;
352     rldicrInstOpcode = ((RLDICR_OPCODE << 26 ) | ( i_Rs << 21 ) | ( i_Ra << 16 ));
353     rldicrInstOpcode |= ( ( i_sh & 0x001F ) << 11 ) | (RLDICR_CONST << 2 );
354     rldicrInstOpcode |= (( i_sh & 0x0020 ) >> 4);
355     rldicrInstOpcode |= (i_me & 0x001F ) << 6;
356     rldicrInstOpcode |= (i_me & 0x0020 );
357     return SWIZZLE_4_BYTE(rldicrInstOpcode);
358 }
359 
360 //-----------------------------------------------------------------------------
361 
getMfsprInstruction(const uint16_t i_Rt,const uint16_t i_sprNum)362 STATIC uint32_t getMfsprInstruction( const uint16_t i_Rt, const uint16_t i_sprNum )
363 {
364     uint32_t mfsprInstOpcode    =   0;
365     mfsprInstOpcode =  (( OPCODE_31 << 26 ) | ( i_Rt << 21 ) | ( i_sprNum << 11 ) | ( MFSPR_CONST << 1 ));
366     return SWIZZLE_4_BYTE(mfsprInstOpcode);
367 }
368 
369 //-----------------------------------------------------------------------------
370 
getBranchLinkRegInstruction(void)371 STATIC uint32_t getBranchLinkRegInstruction(void)
372 {
373     uint32_t branchConstInstOpcode  =   0;
374     branchConstInstOpcode   =   (( OPCODE_18 << 26 ) | ( SELF_SAVE_FUNC_ADD ) | 0x03 );
375 
376     return SWIZZLE_4_BYTE(branchConstInstOpcode);
377 }
378 //-----------------------------------------------------------------------------
379 
380 /**
381  * @brief looks up entry for given SPR in given thread/core section.
382  * @param[in]   i_pThreadSectLoc    start of given thread section or core section.
383  * @param[in]   i_lookUpKey         search key for lookup of given SPR entry.
384  * @param[in]   i_isThreadReg       true if register is of scope thread, false
385  *                                  otherwise.
386  * @param[in|out] io_pSprEntryLoc   Input:  NULL
387  *                                  Output: location of given entry or end of table.
388  * @return      STOP_SAVE_SUCCESS if entry is found, STOP_SAVE_FAIL in case of
389  *              an error.
390  */
lookUpSprInImage(uint32_t * i_pThreadSectLoc,const uint32_t i_lookUpKey,const bool i_isThreadReg,void ** io_pSprEntryLoc,uint8_t i_selfRestVer)391 STATIC StopReturnCode_t lookUpSprInImage( uint32_t* i_pThreadSectLoc, const uint32_t i_lookUpKey,
392                                           const bool i_isThreadReg, void** io_pSprEntryLoc,
393                                           uint8_t i_selfRestVer )
394 {
395     StopReturnCode_t l_rc       =   STOP_SAVE_FAIL;
396     uint32_t temp               =   0;
397     uint32_t* i_threadSectEnd   =   NULL;
398     uint32_t bctr_inst          =   SWIZZLE_4_BYTE(BLR_INST);
399     *io_pSprEntryLoc            =   NULL;
400 
401     do
402     {
403         if( !i_pThreadSectLoc )
404         {
405             MY_ERR( "Bad SPR Start Location" );
406             break;
407         }
408 
409         if( i_selfRestVer )
410         {
411             temp    =   i_isThreadReg ? (uint32_t)(SMF_CORE_RESTORE_THREAD_AREA_SIZE) :
412                                         (uint32_t)(SMF_CORE_RESTORE_CORE_AREA_SIZE);
413 
414         }
415         else
416         {
417             temp    =   i_isThreadReg ? (uint32_t)(CORE_RESTORE_THREAD_AREA_SIZE) :
418                                         (uint32_t)(CORE_RESTORE_CORE_AREA_SIZE);
419         }
420 
421 
422         i_threadSectEnd             =   i_pThreadSectLoc + ( temp >> 2 );
423 
424         temp = 0;
425 
426         while( ( i_pThreadSectLoc <= i_threadSectEnd ) &&
427                ( temp != bctr_inst ) )
428         {
429             temp = *i_pThreadSectLoc;
430 
431             if( ( temp == i_lookUpKey ) || ( temp == bctr_inst ) )
432             {
433                 *io_pSprEntryLoc = i_pThreadSectLoc;
434                 l_rc = STOP_SAVE_SUCCESS;
435                 break;
436             }
437 
438             i_pThreadSectLoc = i_pThreadSectLoc + SIZE_PER_SPR_RESTORE_INST;
439         }
440     }
441     while(0);
442 
443     return l_rc;
444 }
445 
446 //-----------------------------------------------------------------------------
447 
448 /**
449  * @brief updates an SPR STOP image entry.
450  * @param[in] i_pSprEntryLocation location of entry.
451  * @param[in] i_regId       register Id associated with SPR.
452  * @param[in] i_regData     data needs to be written to SPR entry.
453  * @return    STOP_SAVE_SUCCESS if update works, STOP_SAVE_FAIL otherwise.
454  */
updateSprEntryInImage(uint32_t * i_pSprEntryLocation,const CpuReg_t i_regId,const uint64_t i_regData,const enum SprEntryUpdateMode i_mode)455 STATIC StopReturnCode_t updateSprEntryInImage( uint32_t* i_pSprEntryLocation,
456         const CpuReg_t i_regId,
457         const uint64_t i_regData,
458         const enum SprEntryUpdateMode i_mode
459                                              )
460 {
461     StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
462     uint32_t tempInst       =   0;
463     uint64_t tempRegData    =   0;
464     bool newEntry           =   true;
465     uint16_t regRs          =   0; //to use R0 for SPR restore insruction generation
466     uint16_t regRa          =   0;
467 
468     do
469     {
470         if( !i_pSprEntryLocation )
471         {
472             MY_ERR("invalid location of SPR image entry" );
473             l_rc = STOP_SAVE_FAIL;
474             break;
475         }
476 
477         tempInst = genKeyForSprLookup( i_regId );
478 
479         if( *i_pSprEntryLocation == tempInst )
480         {
481             newEntry = false;
482         }
483 
484         //Add SPR search instruction i.e. "ori r0, r0, SPRID"
485         *i_pSprEntryLocation = tempInst;
486         i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
487 
488         if( INIT_SPR_REGION  == i_mode )
489         {
490             //adding inst 'b . + 0x1C'
491             *i_pSprEntryLocation = SWIZZLE_4_BYTE(SKIP_SPR_REST_INST);
492         }
493         else
494         {
495             //clear R0 i.e. "xor ra, rs, rb"
496             tempInst = getXorInstruction( regRs, regRs, regRs );
497             *i_pSprEntryLocation = tempInst;
498         }
499 
500 
501         i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
502 
503         tempRegData = i_regData >> 48;
504         //get lower order 16 bits of SPR restore value in R0
505         tempInst = getOrisInstruction( regRs, regRa, (uint16_t)tempRegData );
506         *i_pSprEntryLocation = tempInst;
507         i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
508 
509         tempRegData = ((i_regData >> 32) & 0x0000FFFF );
510         //get bit b16-b31 of SPR restore value in R0
511         tempInst = getOriInstruction( regRs, regRa, (uint16_t)tempRegData );
512         *i_pSprEntryLocation = tempInst;
513         i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
514 
515         //Rotate R0 to left by  32 bit position and zero lower order 32 bits.
516         //Place the result in R0
517         tempInst = getRldicrInstruction(regRa, regRs, 32, 31);
518         *i_pSprEntryLocation = tempInst;
519         i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
520 
521         tempRegData = ((i_regData >> 16) & 0x000000FFFF );
522         //get bit b32-b47 of SPR restore value to R0
523         tempInst = getOrisInstruction( regRs, regRa, (uint16_t)tempRegData );
524         *i_pSprEntryLocation = tempInst;
525         i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
526 
527         tempRegData = (uint16_t)i_regData;
528         //get bit b48-b63 of SPR restore value to R0
529         tempInst = getOriInstruction( regRs, regRa, (uint16_t)i_regData );
530         *i_pSprEntryLocation = tempInst;
531         i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
532 
533         if( P9_STOP_SPR_MSR == i_regId )
534         {
535             //MSR cannot be restored completely with mtmsrd instruction.
536             //as it does not update ME, LE and HV bits. In self restore code
537             //inorder to restore MSR, contents of R21 is moved to SRR1. It also
538             //executes an RFID which causes contents of SRR1 to be copied to
539             //MSR. This allows copy of LE bit which are specifically interested
540             //in. Instruction below moves contents of MSR Value (in R0 ) to R21.
541             tempInst = SWIZZLE_4_BYTE( MR_R0_TO_R21 );
542         }
543         else if ( P9_STOP_SPR_HRMOR == i_regId )
544         {
545             //Case HRMOR, move contents of R0 to a placeholder GPR (R10)
546             //Thread Launcher expects HRMOR value in R10
547             tempInst = SWIZZLE_4_BYTE( MR_R0_TO_R10 );
548         }
549         else if( P9_STOP_SPR_URMOR == i_regId )
550         {
551             //Case URMOR, move contents of R0 to a placeholder GPR (R9)
552             //Thread Launcher expects URMOR value in R9
553             tempInst = SWIZZLE_4_BYTE( MR_R0_TO_R9 );
554         }
555         else
556         {
557             // Case other SPRs, move contents of R0 to SPR
558             // For a UV system, even HRMOR is treated like any other SPR.
559             tempInst =
560                 getMtsprInstruction( 0, (uint16_t)i_regId );
561         }
562 
563         *i_pSprEntryLocation = tempInst;
564 
565         if( newEntry )
566         {
567             i_pSprEntryLocation += SIZE_PER_SPR_RESTORE_INST;
568             //at the end of SPR restore, add instruction BLR to go back to thread
569             //launcher.
570             tempInst = SWIZZLE_4_BYTE(BLR_INST);
571             *i_pSprEntryLocation = tempInst;
572         }
573     }
574     while(0);
575 
576     return l_rc;
577 }
578 
579 //-----------------------------------------------------------------------------
580 
initSelfSaveEntry(void * const i_pImage,uint16_t i_sprNum)581 STATIC StopReturnCode_t initSelfSaveEntry( void* const i_pImage, uint16_t i_sprNum )
582 {
583     StopReturnCode_t l_rc   =   STOP_SAVE_SUCCESS;
584     uint32_t* i_pSprSave    =   (uint32_t*)i_pImage;
585 
586     //ori r0, r0, 0x00nn
587     *i_pSprSave         =   getOriInstruction( 0, 0, i_sprNum );
588 
589     i_pSprSave++;
590 
591     //addi r31, r31, 0x20
592     *i_pSprSave         =   SWIZZLE_4_BYTE(SKIP_SPR_SELF_SAVE);
593     i_pSprSave++;
594 
595     //nop
596     *i_pSprSave         =   getOriInstruction( 0, 0, 0 );;
597     i_pSprSave++;
598 
599     //mtlr, r30
600     *i_pSprSave         =   SWIZZLE_4_BYTE( MTLR_INST );
601     i_pSprSave++;
602 
603     //blr
604     *i_pSprSave         =   SWIZZLE_4_BYTE(BLR_INST);
605     i_pSprSave++;
606 
607     return l_rc;
608 }
609 
610 //-----------------------------------------------------------------------------
611 
getSprRegIndexAdjustment(const uint32_t i_saveMaskPos,uint32_t * i_sprAdjIndex)612 STATIC StopReturnCode_t getSprRegIndexAdjustment( const uint32_t i_saveMaskPos, uint32_t* i_sprAdjIndex )
613 {
614     StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
615 
616     do
617     {
618         if( (( i_saveMaskPos >= SPR_BIT_POS_8 ) && ( i_saveMaskPos <= SPR_BIT_POS_19 )) ||
619             (( i_saveMaskPos >= SPR_BIT_POS_25 ) && ( i_saveMaskPos <= SPR_BIT_POS_27 )) )
620         {
621             l_rc = STOP_SAVE_SPR_BIT_POS_RESERVE;
622             break;
623         }
624 
625         if( (i_saveMaskPos > SPR_BIT_POS_19) && (i_saveMaskPos < SPR_BIT_POS_25 ) )
626         {
627             *i_sprAdjIndex    =   12;
628         }
629         else if( i_saveMaskPos > SPR_BIT_POS_27 )
630         {
631             *i_sprAdjIndex    =   15;
632         }
633         else
634         {
635             *i_sprAdjIndex   =   0;
636         }
637 
638     }
639     while(0);
640 
641     return l_rc;
642 }
643 //-----------------------------------------------------------------------------
p9_stop_save_cpureg(void * const i_pImage,const CpuReg_t i_regId,const uint64_t i_regData,const uint64_t i_pir)644 StopReturnCode_t p9_stop_save_cpureg(  void* const i_pImage,
645                                        const CpuReg_t  i_regId,
646                                        const uint64_t  i_regData,
647                                        const uint64_t  i_pir )
648 {
649     StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;    // procedure return code
650     HomerSection_t*     chipHomer       =    NULL;
651     SmfHomerSection_t*  smfChipHomer    =    NULL;
652 
653     do
654     {
655         uint32_t threadId       =   0;
656         uint32_t coreId         =   0;
657         uint32_t lookUpKey      =   0;
658         void* pSprEntryLocation =   NULL;   // an offset w.r.t. to start of image
659         void* pThreadLocation   =   NULL;
660         bool threadScopeReg     =   false;
661         uint8_t l_urmorFix      =   false;
662         uint64_t  l_sprValue    =   0;
663         uint8_t l_selfRestVer   =   0;
664 
665         MY_INF(">> p9_stop_save_cpureg" );
666 
667         l_rc = getCoreAndThread( i_pImage, i_pir, &coreId, &threadId );
668 
669         if( l_rc )
670         {
671             MY_ERR("Failed to determine Core Id and Thread Id from PIR 0x%016llx",
672                    i_pir);
673             break;
674         }
675 
676         MY_INF( " PIR 0x%016llx coreId %d threadid %d "
677                 " registerId %d", i_pir, coreId,
678                 threadId, i_regId );
679 
680         // First of all let us validate all input arguments.
681         l_rc =  validateSprImageInputs( i_pImage,
682                                         i_regId,
683                                         coreId,
684                                         &threadId,
685                                         &threadScopeReg );
686 
687         if( l_rc )
688         {
689             // Error: bad argument traces out error code
690             MY_ERR("Bad input argument rc %d", l_rc );
691 
692             break;
693         }
694 
695         l_urmorFix      =   *(uint8_t*)((uint8_t*)i_pImage + CPMR_HOMER_OFFSET + CPMR_URMOR_FIX_BYTE);
696         l_selfRestVer   =   *(uint8_t *)((uint8_t *)i_pImage + CPMR_HOMER_OFFSET + CPMR_SELF_RESTORE_VER_BYTE );
697 
698         if( l_selfRestVer )
699         {
700             smfChipHomer = ( SmfHomerSection_t*)i_pImage;
701 
702             if( threadScopeReg )
703             {
704                 pThreadLocation =
705                     &(smfChipHomer->iv_coreThreadRestore[coreId].iv_threadRestoreArea[threadId][0]);
706             }
707             else
708             {
709                 pThreadLocation =
710                     &(smfChipHomer->iv_coreThreadRestore[coreId].iv_coreRestoreArea[0]);
711             }
712         }
713         else    //Old fips or OPAL release that doesn't support SMF
714         {
715             chipHomer = (HomerSection_t*)i_pImage;
716 
717             if( threadScopeReg )
718             {
719                 pThreadLocation =
720                     &(chipHomer->iv_coreThreadRestore[coreId][threadId].iv_threadArea[0]);
721             }
722             else
723             {
724                 pThreadLocation =
725                     &(chipHomer->iv_coreThreadRestore[coreId][threadId].iv_coreArea[0]);
726             }
727         }
728 
729         if( ( SWIZZLE_4_BYTE(BLR_INST) == *(uint32_t*)pThreadLocation ) ||
730             ( SWIZZLE_4_BYTE(ATTN_OPCODE) == *(uint32_t*) pThreadLocation ) )
731         {
732             // table for given core id doesn't exit. It needs to be
733             // defined.
734             pSprEntryLocation = pThreadLocation;
735         }
736         else
737         {
738             // an SPR restore section for given core already exists
739             lookUpKey = genKeyForSprLookup( i_regId );
740             l_rc = lookUpSprInImage( (uint32_t*)pThreadLocation,
741                                      lookUpKey,
742                                      threadScopeReg,
743                                      &pSprEntryLocation,
744                                      l_selfRestVer );
745         }
746 
747         if( l_rc )
748         {
749             MY_ERR("Invalid or corrupt SPR entry. CoreId 0x%08x threadId ",
750                    "0x%08x regId 0x%08x lookUpKey 0x%08x pThreadLocation 0x%08x"
751                    , coreId, threadId, i_regId, lookUpKey, pThreadLocation );
752             break;
753         }
754 
755         if( ( P9_STOP_SPR_URMOR == i_regId ) && ( l_urmorFix ) )
756         {
757             l_sprValue  =  i_regData - URMOR_CORRECTION;
758         }
759         else
760         {
761             l_sprValue  =  i_regData;
762         }
763 
764         l_rc = updateSprEntryInImage( (uint32_t*) pSprEntryLocation,
765                                       i_regId,
766                                       l_sprValue,
767                                       UPDATE_SPR_ENTRY );
768 
769         if( l_rc )
770         {
771             MY_ERR( " Failed to update the SPR entry of PIR 0x%08x reg"
772                     "0x%08x", i_pir, i_regId );
773             break;
774         }
775 
776     }
777     while(0);
778 
779     MY_INF("<< p9_stop_save_cpureg" );
780     return l_rc;
781 }
782 
783 //-----------------------------------------------------------------------------
784 
785 /**
786  * @brief validates all the input arguments.
787  * @param[in]   i_pImage       pointer to start of HOMER of image for proc chip.
788  * @param[in]   i_scomAddress SCOM address of register.
789  * @param[in]   i_chipletId   core or cache chiplet id
790  * @param[in]   i_operation   operation requested for SCOM entry.
791  * @param[in]   i_section     image section on which operation is to be performed
792  * @return      STOP_SAVE_SUCCESS if arguments found valid, error code otherwise.
793  * @note        Function does not validate that the given SCOM address really
794  *              belongs to the given section.
795  */
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)796 STATIC StopReturnCode_t validateScomImageInputs( void* const i_pImage,
797         const uint32_t i_scomAddress,
798         const uint8_t i_chipletId,
799         const ScomOperation_t i_operation,
800         const ScomSection_t i_section )
801 {
802     StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
803 
804     do
805     {
806         if( !i_pImage )
807         {
808             //Error Invalid image pointer
809             l_rc = STOP_SAVE_ARG_INVALID_IMG;
810             MY_ERR("invalid image location ");
811             break;
812         }
813 
814         if( 0 == i_scomAddress )
815         {
816             l_rc = STOP_SAVE_SCOM_INVALID_ADDRESS;
817             MY_ERR("invalid SCOM address");
818             break;
819         }
820 
821         if(( CACHE_CHIPLET_ID_MIN > i_chipletId ) ||
822            ( CORE_CHIPLET_ID_MAX < i_chipletId ))
823         {
824             l_rc = STOP_SAVE_SCOM_INVALID_CHIPLET;
825             MY_ERR("chiplet id not in range");
826             break;
827         }
828 
829         if(( CORE_CHIPLET_ID_MIN >  i_chipletId ) &&
830            ( CACHE_CHIPLET_ID_MAX < i_chipletId ))
831         {
832             l_rc = STOP_SAVE_SCOM_INVALID_CHIPLET;
833             MY_ERR("chiplet id not valid");
834             break;
835         }
836 
837         if(( P9_STOP_SCOM_OP_MIN >= i_operation ) ||
838            ( P9_STOP_SCOM_OP_MAX <= i_operation ))
839         {
840             //invalid SCOM image operation requested
841             l_rc = STOP_SAVE_SCOM_INVALID_OPERATION;
842             MY_ERR("invalid SCOM image operation");
843             break;
844         }
845 
846         if(( P9_STOP_SECTION_MIN >= i_section ) ||
847            ( P9_STOP_SECTION_MAX <= i_section ))
848         {
849             // invalid cache sub section specified
850             l_rc = STOP_SAVE_SCOM_INVALID_SECTION;
851             MY_ERR("invalid section");
852             break;
853         }
854 
855         if(( i_operation == P9_STOP_SCOM_RESET ) &&
856            ( i_chipletId <  CORE_CHIPLET_ID_MIN ))
857         {
858             // replace requested with a cache chiplet Id
859             l_rc = STOP_SAVE_SCOM_INVALID_OPERATION;
860             MY_ERR( "reset not supported for cache. chiplet Id 0x%08x",
861                     i_chipletId );
862             break;
863         }
864 
865     }
866     while(0);
867 
868     if( l_rc )
869     {
870         MY_ERR("image 0x%08x SCOMAddress 0x%08x chipletId 0x%08x operation"
871                "0x%08x section 0x%08x", i_pImage, i_scomAddress, i_chipletId,
872                i_operation, i_section );
873     }
874 
875     return l_rc;
876 }
877 
878 //-----------------------------------------------------------------------------
879 
880 /**
881  * @brief   edit SCOM entry associated with the given core.
882  * @param[in]   i_scomAddr       SCOM address of register.
883  * @param[in]   i_scomData      data associated with SCOM register.
884  * @param[in]   i_pEntryLocation points to a SCOM entry in HOMER image.
885  * @param[in]   i_operation     operation to be performed on SCOM entry.
886  * @return      STOP_SAVE_SUCCESS if existing entry is updated, STOP_SAVE_FAIL
887  *              otherwise.
888  */
editScomEntry(uint32_t i_scomAddr,uint64_t i_scomData,ScomEntry_t * i_pEntryLocation,uint32_t i_operation)889 STATIC StopReturnCode_t editScomEntry( uint32_t i_scomAddr, uint64_t i_scomData,
890                                        ScomEntry_t* i_pEntryLocation,
891                                        uint32_t i_operation )
892 {
893     StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
894 
895     do
896     {
897         if( !i_pEntryLocation )
898         {
899             //Error: location of SCOM entry is not known
900             //therefore no point moving forward
901             MY_ERR("SCOM entry location not valid");
902             l_rc = STOP_SAVE_FAIL;
903             break;
904         }
905 
906         switch( i_operation )
907         {
908             case P9_STOP_SCOM_OR:
909                 i_pEntryLocation->scomEntryData |= i_scomData;
910                 break;
911 
912             case P9_STOP_SCOM_AND:
913                 i_pEntryLocation->scomEntryData &= i_scomData;
914                 break;
915 
916             case P9_STOP_SCOM_NOOP:
917                 {
918                     uint32_t nopInst = getOriInstruction( 0, 0, 0 );
919                     i_pEntryLocation->scomEntryHeader   =   SWIZZLE_4_BYTE(SCOM_ENTRY_START);
920                     i_pEntryLocation->scomEntryData     =   nopInst;
921                     i_pEntryLocation->scomEntryAddress  =   nopInst;
922                 }
923                 break;
924 
925             case P9_STOP_SCOM_APPEND:
926                 i_pEntryLocation->scomEntryHeader       =   SWIZZLE_4_BYTE(SCOM_ENTRY_START);
927                 i_pEntryLocation->scomEntryData         =   i_scomData;
928                 i_pEntryLocation->scomEntryAddress      =   i_scomAddr;
929                 break;
930         }
931 
932     }
933     while(0);
934 
935     return l_rc;
936 }
937 
938 //-----------------------------------------------------------------------------
939 
940 /**
941  * @brief   update SCOM entry associated with the given core.
942  * @param[in]   i_scomAddr   SCOM address of register.
943  * @param[in]   i_scomData   data associated with SCOM register.
944  * @param[in]   i_scomEntry  points to a SCOM entry in cache section of HOMER image.
945  * @return      STOP_SAVE_SUCCESS if new  entry is added, STOP_SAVE_FAIL otherwise.
946  * @note        adds an entry at a given location. It can be used to add entry in
947  *              place of NOP, at the end of table or as first entry of the cache
948  *              sub-section(L2, L3 or EQ ).
949  */
updateScomEntry(uint32_t i_scomAddr,uint64_t i_scomData,ScomEntry_t * i_scomEntry)950 STATIC StopReturnCode_t updateScomEntry( uint32_t i_scomAddr, uint64_t i_scomData,
951         ScomEntry_t* i_scomEntry   )
952 {
953     StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
954 
955     do
956     {
957         if( !i_scomEntry )
958         {
959             MY_ERR( "cache entry cannot be located");
960             l_rc = STOP_SAVE_SCOM_ENTRY_UPDATE_FAILED;
961             break;
962         }
963 
964         i_scomEntry->scomEntryHeader    =   SWIZZLE_4_BYTE(SCOM_ENTRY_START); // done for now
965         i_scomEntry->scomEntryAddress   =   i_scomAddr;
966         i_scomEntry->scomEntryData      =   i_scomData;
967 
968     }
969     while(0);
970 
971     return l_rc;
972 }
973 
974 //-----------------------------------------------------------------------------
975 /**
976  * @brief populates SCOM restore entry header with version and layout info.
977  * @param[in]   i_scomEntry     points to SCOM restore entry
978  * @param[in]   i_imageVer      SGPE image version
979  * @param[in]   i_maxScomEntry  max SCOM entries supported
980  */
981 
updateEntryHeader(ScomEntry_t * i_scomEntry,uint32_t i_imageVer,uint32_t i_maxScomEntry)982 STATIC void updateEntryHeader( ScomEntry_t* i_scomEntry ,
983                                uint32_t i_imageVer,
984                                uint32_t i_maxScomEntry )
985 {
986     uint32_t l_temp = 0;
987 
988     if( i_imageVer >= STOP_API_VER_CONTROL )
989     {
990         l_temp = ( 0x000000ff & i_maxScomEntry );
991         l_temp |= ( STOP_API_VER  & 0x7 ) << 28;
992         i_scomEntry->scomEntryHeader = SWIZZLE_4_BYTE(l_temp);
993 
994         MY_INF("SCOM Restore Header 0x%08x", l_temp );
995     }
996 }
997 
998 //-----------------------------------------------------------------------------
999 
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)1000 StopReturnCode_t p9_stop_save_scom( void* const   i_pImage,
1001                                     const uint32_t i_scomAddress,
1002                                     const uint64_t i_scomData,
1003                                     const ScomOperation_t i_operation,
1004                                     const ScomSection_t i_section )
1005 {
1006     StopReturnCode_t l_rc = STOP_SAVE_SUCCESS;
1007     uint32_t entryLimit =   0;
1008     uint8_t chipletId   =   0;
1009     uint32_t nopInst    =   0;
1010     uint32_t index      =   0;
1011     uint32_t imageVer   =   0;
1012     uint32_t entrySwzHeader = 0;
1013     uint32_t l_maxScomRestoreEntry = 0;
1014     ScomEntry_t* pScomEntry      =  NULL;
1015     ScomEntry_t* pEntryLocation  =  NULL;
1016     ScomEntry_t* pNopLocation    =  NULL;
1017     ScomEntry_t* pEditScomHeader =  NULL;
1018     StopCacheSection_t* pStopCacheScomStart =   NULL;
1019     ScomEntry_t* pTableEndLocationtable     =   NULL;
1020     uint32_t swizzleAddr;
1021     uint64_t swizzleData;
1022     uint32_t swizzleAttn;
1023     uint32_t swizzleBlr     =   SWIZZLE_4_BYTE(BLR_INST);
1024     bool     cacheEntry     =   true;
1025 
1026     MY_INF(">> p9_stop_save_scom");
1027 
1028     //Reads SGPE image version info from QPMR Header in HOMER
1029     //For backward compatibility, for base version of SGPE Hcode,
1030     //STOP API retains default behavior but adds version specific
1031     //details in each entry in later versions.
1032     imageVer       =  *(uint32_t*)((uint8_t*)i_pImage + QPMR_HOMER_OFFSET + QPMR_BUILD_VER_BYTE);
1033     imageVer       =  SWIZZLE_4_BYTE(imageVer);
1034 
1035 
1036     do
1037     {
1038         chipletId   =   i_scomAddress >> 24;
1039         chipletId   =   chipletId & 0x3F;
1040 
1041         l_rc        =   validateScomImageInputs( i_pImage, i_scomAddress, chipletId, i_operation, i_section );
1042 
1043         if( l_rc )
1044         {
1045             MY_ERR( "invalid argument: aborting");
1046             break;
1047         }
1048 
1049         if( chipletId >= CORE_CHIPLET_ID_MIN )
1050         {
1051             // chiplet is core. So, let us find the start address of SCOM area
1052             // pertaining to a core in STOP image.
1053             l_maxScomRestoreEntry   =
1054                 *(uint32_t*)((uint8_t*)i_pImage + CPMR_HOMER_OFFSET + CPMR_MAX_SCOM_REST_PER_CORE_BYTE);
1055             pScomEntry              =   CORE_ID_SCOM_START(i_pImage, chipletId )
1056             cacheEntry              =   false;
1057 
1058             if( !l_maxScomRestoreEntry )
1059             {
1060                 //Old HB and new STOP API case. Retain legacy Number
1061                 l_maxScomRestoreEntry   =  SWIZZLE_4_BYTE(LEGACY_CORE_SCOM_SUPPORTED);
1062             }
1063         }
1064         else
1065         {
1066             l_maxScomRestoreEntry   =
1067                 *(uint32_t*)((uint8_t*)i_pImage + QPMR_HOMER_OFFSET + QPMR_QUAD_MAX_SCOM_ENTRY_BYTE);
1068 
1069             if( !l_maxScomRestoreEntry )
1070             {
1071                 // Incase of a bad HOMER header initialization, fall back on legacy number.
1072                 l_maxScomRestoreEntry   =  SWIZZLE_4_BYTE(LEGACY_QUAD_SCOM_SUPPORTED);
1073             }
1074             // chiplet is a cache. let us find start address of cache section
1075             // associated with given chiplet. A cache section associated with
1076             // given chiplet is split in to L2, L3 and EQ area.
1077             pStopCacheScomStart = CACHE_SECTN_START(i_pImage,
1078                                                     chipletId);
1079         }
1080 
1081         l_maxScomRestoreEntry   =   SWIZZLE_4_BYTE(l_maxScomRestoreEntry);
1082 
1083         if(( !pStopCacheScomStart ) && ( !pScomEntry) )
1084         {
1085             //Error invalid pointer to SCOM entry in cache or core section
1086             //of STOP image.
1087             MY_ERR("invalid start location for chiplet %d",
1088                    chipletId );
1089             break;
1090         }
1091 
1092         switch( i_section )
1093         {
1094             case P9_STOP_SECTION_EQ_SCOM:
1095                 pScomEntry = pStopCacheScomStart->nonCacheArea;
1096                 entryLimit = MAX_EQ_SCOM_ENTRIES;
1097                 break;
1098 
1099             case P9_STOP_SECTION_L2:
1100                 pScomEntry = pStopCacheScomStart->l2CacheArea;
1101                 entryLimit = MAX_L2_SCOM_ENTRIES;
1102                 break;
1103 
1104             case P9_STOP_SECTION_L3:
1105                 pScomEntry = pStopCacheScomStart->l3CacheArea;
1106                 entryLimit = MAX_L3_SCOM_ENTRIES;
1107                 break;
1108 
1109             case P9_STOP_SECTION_CORE_SCOM:
1110                 //macro CORE_ID_SCOM_START already gives start of scom
1111                 //entry for given core. entry limit too is assigned thereafter.
1112                 //Handling for core and cache segment is different for scom
1113                 //entries. It is because scom entries are organized differently
1114                 //in core and cache segment.
1115 
1116                 entryLimit  =   l_maxScomRestoreEntry;
1117                 break;
1118 
1119             default:
1120                 l_rc = STOP_SAVE_SCOM_INVALID_SECTION;
1121                 break;
1122         }
1123 
1124 
1125         if(( imageVer > LEGACY_SCOM_RESTORE_VER ) && ( cacheEntry ) )
1126         {
1127             //STOP API migrated to newer algorithm for creation of entries
1128 
1129             pScomEntry  =   CACHE_SCOM_ADDR(i_pImage,
1130                                             chipletId,
1131                                             l_maxScomRestoreEntry )
1132 
1133             entryLimit  =   l_maxScomRestoreEntry;
1134         }
1135 
1136         if(( !pScomEntry ) || ( l_rc ) )
1137         {
1138             // Error Invalid pointer to cache entry
1139             MY_ERR("invalid subsection %d or internal firmware failure",
1140                    i_section );
1141             l_rc = STOP_SAVE_FAIL;
1142             break;
1143         }
1144 
1145         nopInst                 =   getOriInstruction( 0, 0, 0 );
1146         pEntryLocation          =   NULL;
1147         pNopLocation            =   NULL;
1148         pTableEndLocationtable  =   NULL;
1149         swizzleAddr             =   SWIZZLE_4_BYTE(i_scomAddress);
1150         swizzleData             =   SWIZZLE_8_BYTE(i_scomData);
1151         swizzleAttn             =   SWIZZLE_4_BYTE(ATTN_OPCODE);
1152 
1153         for( index = 0; index < entryLimit; ++index )
1154         {
1155             uint32_t entrySwzAddress = pScomEntry[index].scomEntryAddress;
1156             entrySwzHeader  = SWIZZLE_4_BYTE(pScomEntry[index].scomEntryHeader);
1157 
1158             if( ( swizzleAddr == entrySwzAddress ) && ( !pEntryLocation ) )
1159 
1160             {
1161                 pEntryLocation = &pScomEntry[index];
1162             }
1163 
1164             if( (( nopInst == entrySwzAddress ) ||
1165                  ( swizzleAttn == entrySwzAddress ) ||
1166                  ( swizzleBlr == entrySwzAddress )) && ( !pNopLocation ) )
1167             {
1168                 pNopLocation = &pScomEntry[index];
1169             }
1170 
1171             // if entry is either 0xDEADDEAD or has SCOM entry limit in LSB of header
1172             // place is already occupied
1173             if( ( SCOM_ENTRY_START == entrySwzHeader ) ||
1174                 ( entrySwzHeader & 0x000000FF ) )
1175             {
1176                 continue;
1177             }
1178 
1179             pTableEndLocationtable = &pScomEntry[index];
1180             break;
1181         }
1182 
1183         if( ( !pEntryLocation ) && ( !pTableEndLocationtable ) )
1184         {
1185             MY_ERR(" exhausted all location available for section"
1186                    "0x%08x scom address 0x%08x",
1187                    i_section, i_scomAddress );
1188             l_rc = STOP_SAVE_SCOM_ENTRY_UPDATE_FAILED;
1189             break;
1190         }
1191 
1192         switch( i_operation )
1193         {
1194             case P9_STOP_SCOM_APPEND:
1195                 {
1196                     ScomEntry_t* pScomAppend = NULL;
1197 
1198                     if( pNopLocation )
1199                     {
1200                         pScomAppend = pNopLocation;
1201                     }
1202                     else
1203                     {
1204                         pScomAppend = pTableEndLocationtable;
1205                     }
1206 
1207                     l_rc = updateScomEntry ( swizzleAddr,
1208                                              swizzleData, pScomAppend );
1209 
1210                     pEditScomHeader = pScomAppend;
1211                 }
1212                 break;
1213 
1214             case P9_STOP_SCOM_REPLACE:
1215                 {
1216                     ScomEntry_t* scomReplace = NULL;
1217 
1218                     if( pEntryLocation )
1219                     {
1220                         scomReplace = pEntryLocation;
1221                     }
1222                     else
1223                     {
1224                         scomReplace = pTableEndLocationtable;
1225                     }
1226 
1227                     l_rc = updateScomEntry( swizzleAddr,
1228                                             swizzleData, scomReplace );
1229 
1230                     pEditScomHeader = scomReplace;
1231                 }
1232                 break;
1233 
1234             case P9_STOP_SCOM_OR:
1235             case P9_STOP_SCOM_AND:
1236             case P9_STOP_SCOM_NOOP:
1237 
1238                 if( pEntryLocation )
1239                 {
1240                     l_rc = editScomEntry( swizzleAddr,
1241                                           swizzleData,
1242                                           pEntryLocation,
1243                                           i_operation );
1244 
1245                     pEditScomHeader = pEntryLocation;
1246                 }
1247                 else
1248                 {
1249                     //Invalid operation requested.
1250                     MY_ERR( "entry not found edit chiplet Id 0x%08x "
1251                             "swizzle addr 0x%08x ",
1252                             chipletId, swizzleAddr );
1253 
1254                     l_rc = STOP_SAVE_SCOM_INVALID_OPERATION;
1255                 }
1256 
1257                 break;
1258 
1259             case P9_STOP_SCOM_RESET:
1260 
1261                 if( P9_STOP_SECTION_CORE_SCOM ==  i_section )
1262                 {
1263                     memset( pScomEntry, 0x00, CORE_SCOM_RESTORE_SIZE_PER_CORE );
1264                 }
1265 
1266                 break;
1267 
1268             case P9_STOP_SCOM_OR_APPEND:
1269             case P9_STOP_SCOM_AND_APPEND:
1270                 {
1271                     uint32_t tempOperation  = P9_STOP_SCOM_APPEND;
1272                     ScomEntry_t* editAppend = NULL;
1273 
1274                     if( NULL == pEntryLocation )
1275                     {
1276                         editAppend = pTableEndLocationtable;
1277                     }
1278                     else
1279                     {
1280                         editAppend = pEntryLocation;
1281 
1282                         if( P9_STOP_SCOM_OR_APPEND == i_operation )
1283                         {
1284                             tempOperation = P9_STOP_SCOM_OR;
1285                         }
1286                         else
1287                         {
1288                             tempOperation = P9_STOP_SCOM_AND;
1289                         }
1290                     }
1291 
1292                     l_rc = editScomEntry( swizzleAddr,
1293                                           swizzleData,
1294                                           editAppend,
1295                                           tempOperation );
1296 
1297                     pEditScomHeader = editAppend;
1298                 }
1299                 break;
1300 
1301             default:
1302                 l_rc = STOP_SAVE_SCOM_INVALID_OPERATION;
1303                 break;
1304         }
1305     }
1306     while(0);
1307 
1308     if( l_rc )
1309     {
1310         MY_ERR("SCOM image operation 0x%08x failed for chiplet 0x%08x addr"
1311                "0x%08x", i_operation, chipletId ,
1312                i_scomAddress );
1313     }
1314     else
1315     {
1316         //Update SCOM Restore entry with version and memory layout
1317         //info
1318         updateEntryHeader( pEditScomHeader, imageVer, l_maxScomRestoreEntry );
1319     }
1320 
1321     MY_INF("<< p9_stop_save_scom");
1322     return l_rc;
1323 }
1324 
1325 //-----------------------------------------------------------------------------
1326 
1327 /**
1328  * @brief   searches a self save entry of an SPR in self-save segment.
1329  * @param[in]   i_sprBitPos         bit position associated with SPR in save mask vector.
1330  * @param[in]   l_pSprSaveStart     start location of SPR save segment
1331  * @param[in]   i_searchLength      length of SPR save segment
1332  * @param[in]   i_pSaveSprLoc       start location of save entry for a given SPR.
1333  * @return      STOP_SAVE_SUCCESS if look up succeeds, error code otherwise.
1334  */
lookUpSelfSaveSpr(uint32_t i_sprBitPos,uint32_t * l_pSprSaveStart,uint32_t i_searchLength,uint32_t ** i_pSaveSprLoc)1335 STATIC StopReturnCode_t lookUpSelfSaveSpr( uint32_t i_sprBitPos, uint32_t* l_pSprSaveStart,
1336                                     uint32_t  i_searchLength, uint32_t** i_pSaveSprLoc )
1337 {
1338     int32_t l_saveWordLength    =   (int32_t)(i_searchLength >> 2);
1339     uint32_t l_oriInst          =   getOriInstruction( 0, 0, i_sprBitPos );
1340     StopReturnCode_t l_rc       =   STOP_SAVE_FAIL;
1341 
1342     while( l_saveWordLength > 0 )
1343     {
1344         if( l_oriInst == *l_pSprSaveStart )
1345         {
1346             *i_pSaveSprLoc   =   l_pSprSaveStart;
1347             l_rc             =   STOP_SAVE_SUCCESS;
1348             break;
1349         }
1350 
1351         l_pSprSaveStart++;
1352         l_saveWordLength--;
1353     }
1354 
1355     return l_rc;
1356 }
1357 
1358 //-----------------------------------------------------------------------------
1359 
1360 /**
1361  * @brief   searches a self save entry of an SPR in self-save segment.
1362  * @param[in]   i_pSaveReg  start of editable location of a SPR save entry.
1363  * @param[in]   i_sprNum    Id of the SPR for which entry needs to be edited.
1364  * @return      STOP_SAVE_SUCCESS if look up succeeds, error code otherwise.
1365  */
updateSelfSaveEntry(uint32_t * i_pSaveReg,uint16_t i_sprNum)1366 STATIC StopReturnCode_t updateSelfSaveEntry( uint32_t* i_pSaveReg, uint16_t i_sprNum )
1367 {
1368     StopReturnCode_t l_rc   =   STOP_SAVE_SUCCESS;
1369 
1370     do
1371     {
1372         if( !i_pSaveReg )
1373         {
1374             l_rc    =   STOP_SAVE_FAIL;
1375             MY_ERR( "Failed to update self save area for SPR 0x%04x", i_sprNum );
1376             break;
1377         }
1378 
1379         if( P9_STOP_SPR_MSR == i_sprNum )
1380         {
1381             *i_pSaveReg     =    getMfmsrInstruction( 1 );
1382         }
1383         else
1384         {
1385             *i_pSaveReg     =   getMfsprInstruction( 1, i_sprNum );
1386         }
1387 
1388         i_pSaveReg++;
1389 
1390         *i_pSaveReg         =   getBranchLinkRegInstruction( );
1391     }
1392     while(0);
1393 
1394     return l_rc;
1395 }
1396 
1397 //-----------------------------------------------------------------------------
1398 
p9_stop_save_cpureg_control(void * i_pImage,const uint64_t i_pir,const uint32_t i_saveRegVector)1399 StopReturnCode_t p9_stop_save_cpureg_control(  void* i_pImage,
1400         const uint64_t i_pir,
1401         const uint32_t i_saveRegVector )
1402 {
1403     StopReturnCode_t l_rc   =   STOP_SAVE_SUCCESS;
1404     uint32_t l_coreId       =   0;
1405     uint32_t l_threadId     =   0;
1406     uint32_t l_sprPos       =   0;
1407     uint32_t l_sprIndex     =   0;
1408     uint32_t l_lookupLength =   0;
1409     uint32_t l_lookUpKey    =   0;
1410     uint32_t* l_pSaveStart          =   NULL;
1411     uint32_t* l_pRestoreStart       =   NULL;
1412     uint32_t* l_pSprSave            =   NULL;
1413     void* l_pTempLoc                =   NULL;
1414     SmfHomerSection_t* l_pHomer     =   NULL;
1415     uint8_t l_selfRestVer           =   0;
1416 
1417     do
1418     {
1419         l_rc    =   getCoreAndThread( i_pImage, i_pir, &l_coreId, &l_threadId );
1420 
1421         if( l_rc )
1422         {
1423             MY_ERR( "Error in getting core no 0x%08x and thread no 0x%08x from PIR 0x%016lx",
1424                     l_coreId, l_threadId, i_pir );
1425             break;
1426         }
1427 
1428         l_rc    =   validateArgumentSaveRegMask( i_pImage, l_coreId, l_threadId, i_saveRegVector );
1429 
1430         if( l_rc )
1431         {
1432             MY_ERR( "Invalid argument rc 0x%08x", (uint32_t) l_rc );
1433             break;
1434         }
1435 
1436         l_pHomer        =   ( SmfHomerSection_t * )i_pImage;
1437         l_selfRestVer   =   *(uint8_t *)((uint8_t *)i_pImage + CPMR_HOMER_OFFSET + CPMR_SELF_RESTORE_VER_BYTE );
1438 
1439         for( l_sprIndex = 0; l_sprIndex < MAX_SPR_SUPPORTED; l_sprIndex++ )
1440         {
1441             l_sprPos    =    g_sprRegister[l_sprIndex].iv_saveMaskPos;
1442 
1443             //Check if a given SPR needs to be self-saved each time on STOP entry
1444 
1445             if( i_saveRegVector & ( TEST_BIT_PATTERN >> l_sprPos ) )
1446             {
1447 
1448                 if( g_sprRegister[l_sprIndex].iv_isThreadScope )
1449                 {
1450                     l_lookupLength  =   SMF_SELF_SAVE_THREAD_AREA_SIZE;
1451                     l_pSaveStart    =
1452                         (uint32_t*)&l_pHomer->iv_coreThreadRestore[l_coreId].iv_threadSaveArea[l_threadId][0];
1453                     l_pRestoreStart =
1454                         (uint32_t*)&l_pHomer->iv_coreThreadRestore[l_coreId].iv_threadRestoreArea[l_threadId][0];
1455                 }
1456                 else
1457                 {
1458                     l_lookupLength  =   SMF_CORE_SAVE_CORE_AREA_SIZE;
1459                     l_pSaveStart    =   (uint32_t*)&l_pHomer->iv_coreThreadRestore[l_coreId].iv_coreSaveArea[0];
1460                     l_pRestoreStart =   (uint32_t*)&l_pHomer->iv_coreThreadRestore[l_coreId].iv_coreRestoreArea[0];
1461                 }
1462 
1463                 // an SPR restore section for given core already exists
1464                 l_lookUpKey   =   genKeyForSprLookup( ( CpuReg_t )g_sprRegister[l_sprIndex].iv_sprId );
1465 
1466                 l_rc          =   lookUpSprInImage( (uint32_t*)l_pRestoreStart, l_lookUpKey,
1467                                                     g_sprRegister[l_sprIndex].iv_isThreadScope, &l_pTempLoc,
1468                                                     l_selfRestVer  );
1469 
1470                 if( l_rc )
1471                 {
1472                     //SPR specified in the save mask but there is no restore entry present in the memory
1473                     //Self-Save instruction will edit it during STOP entry to make it a valid entry
1474 
1475                     l_rc = p9_stop_save_cpureg( i_pImage,
1476                                                 (CpuReg_t)g_sprRegister[l_sprIndex].iv_sprId,
1477                                                 0x00,       //creates a dummy entry
1478                                                 i_pir );
1479                 }
1480 
1481                 //Find if SPR-Save eye catcher exist in self-save segment of SPR restore region.
1482                 l_rc  =   lookUpSelfSaveSpr( l_sprPos, l_pSaveStart, l_lookupLength, &l_pSprSave );
1483 
1484                 if( l_rc )
1485                 {
1486                     MY_INF( "Failed to find SPR No %02d save entry", l_sprPos );
1487                     l_rc    =  STOP_SAVE_SPR_ENTRY_MISSING;
1488                     break;
1489                 }
1490 
1491                 l_pSprSave++; //point to next instruction location
1492 
1493                 //update specific instructions of self save region to enable saving for SPR
1494                 l_rc    =   updateSelfSaveEntry( l_pSprSave, g_sprRegister[l_sprIndex].iv_sprId );
1495 
1496             }// end if( i_saveRegVector..)
1497         }// end for
1498     }
1499     while(0);
1500 
1501     return l_rc;
1502 }
1503 
1504 //-----------------------------------------------------------------------------------------------------
1505 
p9_stop_init_cpureg(void * const i_pImage,const uint32_t i_corePos)1506 StopReturnCode_t p9_stop_init_cpureg(  void* const i_pImage, const uint32_t i_corePos )
1507 {
1508     StopReturnCode_t    l_rc        =   STOP_SAVE_SUCCESS;
1509     uint32_t* l_pRestoreStart       =   NULL;
1510     void* l_pTempLoc                =   NULL;
1511     SmfHomerSection_t* l_pHomer     =   NULL;
1512     uint32_t l_threadPos            =   0;
1513     uint32_t l_lookUpKey            =   0;
1514     uint32_t l_sprIndex             =   0;
1515     uint8_t l_selfRestVer           =   0;
1516 
1517     MY_INF( ">> p9_stop_init_cpureg" );
1518 
1519     do
1520     {
1521         if( !i_pImage )
1522         {
1523             l_rc    =   STOP_SAVE_ARG_INVALID_IMG;
1524             break;
1525         }
1526 
1527         if( i_corePos > MAX_CORE_ID_SUPPORTED )
1528         {
1529             l_rc    =  STOP_SAVE_ARG_INVALID_CORE;
1530             break;
1531         }
1532 
1533         l_pHomer        =   ( SmfHomerSection_t * ) i_pImage;
1534         l_selfRestVer   =   *(uint8_t *)((uint8_t *)i_pImage + CPMR_HOMER_OFFSET + CPMR_SELF_RESTORE_VER_BYTE );
1535 
1536         for( l_sprIndex = 0; l_sprIndex < MAX_SPR_SUPPORTED; l_sprIndex++ )
1537         {
1538             //Check if a given SPR needs to be self-saved each time on STOP entry
1539 
1540             l_lookUpKey     =   genKeyForSprLookup( ( CpuReg_t )g_sprRegister[l_sprIndex].iv_sprId );
1541 
1542             if( g_sprRegister[l_sprIndex].iv_isThreadScope )
1543             {
1544                 for( l_threadPos = 0; l_threadPos < MAX_THREADS_PER_CORE; l_threadPos++ )
1545                 {
1546                     l_pRestoreStart =
1547                         (uint32_t*)&l_pHomer->iv_coreThreadRestore[i_corePos].iv_threadRestoreArea[l_threadPos][0];
1548 
1549                     l_rc    =   lookUpSprInImage( (uint32_t*)l_pRestoreStart, l_lookUpKey,
1550                                                   g_sprRegister[l_sprIndex].iv_isThreadScope,
1551                                                   &l_pTempLoc,
1552                                                   l_selfRestVer );
1553 
1554                     if( l_rc )
1555                     {
1556                         MY_ERR( "Thread SPR lookup failed in p9_stop_init_cpureg SPR %d Core %d Thread %d Index %d",
1557                                 g_sprRegister[l_sprIndex].iv_sprId, i_corePos, l_threadPos, l_sprIndex );
1558                         break;
1559                     }
1560 
1561                     l_rc = updateSprEntryInImage( (uint32_t*) l_pTempLoc,
1562                                                   ( CpuReg_t )g_sprRegister[l_sprIndex].iv_sprId,
1563                                                   0x00,
1564                                                   INIT_SPR_REGION );
1565 
1566                     if( l_rc )
1567                     {
1568                         MY_ERR( "Thread SPR region init failed. Core %d SPR Id %d",
1569                                 i_corePos, g_sprRegister[l_sprIndex].iv_sprId );
1570                         break;
1571                     }
1572 
1573                 }//end for thread
1574 
1575                 if( l_rc )
1576                 {
1577                     break;
1578                 }
1579 
1580             }//end if SPR threadscope
1581             else
1582             {
1583                 l_pRestoreStart     =   (uint32_t*)&l_pHomer->iv_coreThreadRestore[i_corePos].iv_coreRestoreArea[0];
1584 
1585                 l_rc                =   lookUpSprInImage( (uint32_t*)l_pRestoreStart, l_lookUpKey,
1586                                         g_sprRegister[l_sprIndex].iv_isThreadScope,
1587                                         &l_pTempLoc, l_selfRestVer );
1588 
1589                 if( l_rc )
1590                 {
1591                     MY_ERR( "Core SPR lookup failed in p9_stop_init_cpureg" );
1592                     break;
1593                 }
1594 
1595                 l_rc    =   updateSprEntryInImage( (uint32_t*) l_pTempLoc,
1596                                                    ( CpuReg_t )g_sprRegister[l_sprIndex].iv_sprId,
1597                                                    0x00,
1598                                                    INIT_SPR_REGION );
1599 
1600                 if( l_rc )
1601                 {
1602                     MY_ERR( "Core SPR region init failed. Core %d SPR Id %d SPR Index %d",
1603                             i_corePos, g_sprRegister[l_sprIndex].iv_sprId, l_sprIndex );
1604                     break;
1605                 }
1606 
1607             }// end else
1608 
1609         }// end for l_sprIndex
1610 
1611     }
1612     while(0);
1613 
1614     MY_INF( "<< p9_stop_init_cpureg" );
1615     return l_rc;
1616 }
1617 
1618 //-----------------------------------------------------------------------------------------------------
1619 
p9_stop_init_self_save(void * const i_pImage,const uint32_t i_corePos)1620 StopReturnCode_t p9_stop_init_self_save(  void* const i_pImage, const uint32_t i_corePos )
1621 {
1622     StopReturnCode_t    l_rc        =   STOP_SAVE_SUCCESS;
1623     uint32_t* l_pSaveStart          =   NULL;
1624     SmfHomerSection_t *  l_pHomer   =   NULL;
1625     uint32_t l_threadPos            =   0;
1626     uint32_t l_sprBitPos            =   0;
1627     uint32_t l_sprIndexAdj          =   0;
1628     MY_INF( ">> p9_stop_init_self_save" );
1629 
1630     do
1631     {
1632         if( !i_pImage )
1633         {
1634             l_rc    =   STOP_SAVE_ARG_INVALID_IMG;
1635             break;
1636         }
1637 
1638         if( i_corePos > MAX_CORE_ID_SUPPORTED )
1639         {
1640             l_rc    =  STOP_SAVE_ARG_INVALID_CORE;
1641             break;
1642         }
1643 
1644         l_pHomer    =   ( SmfHomerSection_t*) i_pImage;
1645 
1646         for( l_threadPos = 0; l_threadPos < MAX_THREADS_PER_CORE; l_threadPos++ )
1647         {
1648             l_pSaveStart    =
1649                 (uint32_t*)&l_pHomer->iv_coreThreadRestore[i_corePos].iv_threadSaveArea[l_threadPos][0];
1650 
1651             //Adding instruction 'mflr r30'
1652             *l_pSaveStart   =   SWIZZLE_4_BYTE(MFLR_R30);
1653             l_pSaveStart++;
1654 
1655             for( l_sprBitPos  = 0; l_sprBitPos <= MAX_SPR_BIT_POS; l_sprBitPos++ )
1656             {
1657                 l_rc = getSprRegIndexAdjustment( l_sprBitPos, &l_sprIndexAdj );
1658 
1659                 if( STOP_SAVE_SPR_BIT_POS_RESERVE == l_rc )
1660                 {
1661                     //Failed to find SPR index adjustment
1662                     continue;
1663                 }
1664 
1665                 if( !g_sprRegister[l_sprBitPos - l_sprIndexAdj].iv_isThreadScope )
1666                 {
1667                     continue;
1668                 }
1669 
1670                 //Initialize self save region with SPR save entry for each thread
1671                 //level SPR
1672                 l_rc    =   initSelfSaveEntry( l_pSaveStart,
1673                                                g_sprRegister[l_sprBitPos - l_sprIndexAdj].iv_saveMaskPos );
1674 
1675                 if( l_rc )
1676                 {
1677                     MY_ERR( "Failed to init thread self-save region for core %d thread %d",
1678                             i_corePos, l_threadPos );
1679                     break;
1680                 }
1681 
1682                 l_pSaveStart++;
1683                 l_pSaveStart++;
1684                 l_pSaveStart++;
1685             }
1686 
1687         }// for thread = 0;
1688 
1689         if( l_rc )
1690         {
1691             //breakout if saw an error while init of thread SPR region
1692             break;
1693         }
1694 
1695         l_pSaveStart    =
1696             (uint32_t*)&l_pHomer->iv_coreThreadRestore[i_corePos].iv_coreSaveArea[0];
1697 
1698         *l_pSaveStart   =   SWIZZLE_4_BYTE(MFLR_R30);
1699         l_pSaveStart++;
1700 
1701         for( l_sprBitPos = 0;  l_sprBitPos <=  MAX_SPR_BIT_POS; l_sprBitPos++ )
1702         {
1703             l_rc = getSprRegIndexAdjustment( l_sprBitPos, &l_sprIndexAdj );
1704 
1705             if( STOP_SAVE_SPR_BIT_POS_RESERVE == l_rc )
1706             {
1707                 //Failed to find SPR index adjustment
1708                 continue;
1709             }
1710 
1711             if( g_sprRegister[l_sprBitPos - l_sprIndexAdj].iv_isThreadScope )
1712             {
1713                 continue;
1714             }
1715 
1716             //Initialize self save region with SPR save entry for each core
1717             //level SPR
1718             l_rc    =   initSelfSaveEntry( l_pSaveStart,
1719                                            g_sprRegister[l_sprBitPos - l_sprIndexAdj].iv_saveMaskPos );
1720 
1721             if( l_rc )
1722             {
1723                 MY_ERR( "Failed to init core self-save region for core %d thread %d",
1724                         i_corePos, l_threadPos );
1725                 break;
1726             }
1727 
1728             l_pSaveStart++;
1729             l_pSaveStart++;
1730             l_pSaveStart++;
1731         }
1732     }
1733     while(0);
1734 
1735     MY_INF( "<< p9_stop_init_self_save" );
1736     return l_rc;
1737 }
1738 
1739 #ifdef __cplusplus
1740 } //namespace stopImageSection ends
1741 
1742 }  //extern "C"
1743 #endif
1744