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