Nate, GCC generates assembly code that uses RBP to store Private local variable for below C code in PeiCore/Dispatcher.c

      if (StackOffsetPositive) {
        SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData + StackOffset);
        Private     = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private + StackOffset);
      } else {
        SecCoreData = (CONST EFI_SEC_PEI_HAND_OFF *)((UINTN)(VOID *)SecCoreData - StackOffset);
        Private     = (PEI_CORE_INSTANCE *)((UINTN)(VOID *)Private - StackOffset);
      }

      TemporaryRamSupportPpi->TemporaryRamMigration (
                                PeiServices,
                                TemporaryRamBase,
                                (EFI_PHYSICAL_ADDRESS)(UINTN)(TopOfNewStack - TemporaryStackSize),
                                TemporaryRamSize
                                );

      PeiCore (SecCoreData, NULL, Private);

If TemporaryRamMigration() updates the RBP to point to physical memory by adding/subtracting the StackOffset, that results the Private is added/subtracted by StackOffset twice: One in the C code before calling TemporayRamSupport PPI, the other in TemporaryRamMigration ().

Since FspSecMain.SecSwitchStack() does update the RBP, have you met the similar issue?

The issue doesn't always happen. It depends on whether RBP is used to store either SecCoreData or Private.