/*************************************************************************
* Copyright (C) 2001 Intel Corporation
*
* Licensed under the Apache License,  Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 	http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law  or agreed  to  in  writing,  software
* distributed under  the License  is  distributed  on  an  "AS IS"  BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the  specific  language  governing  permissions  and
* limitations under the License.
*************************************************************************/

//
//  Intel® Cryptography Primitives Library
//

#include "owndefs.h"
#include "ippcpdefs.h"
#include "ippcp.h"
#include "dispatcher.h"

#if defined(_IPP_DATA)

static Ipp64u cpFeatures     = 0;
static Ipp64u cpFeaturesMask = 0;

static int cpGetFeatures(Ipp64u* pFeaturesMask);

/* clang-format off */
extern IPP_OWN_DECL (void, cpGetReg, ( int* buf, int valEAX, int valECX ))
extern IPP_OWN_DECL (int,  cp_is_avx_extension, ( void ))
extern IPP_OWN_DECL (int,  cp_is_avx512_extension, ( void ))
extern IPP_OWN_DECL (int,  cp_issue_avx512_instruction, ( void ))

    /* clang-format on */
    IppStatus owncpSetCpuFeaturesAndIdx(Ipp64u cpuFeatures, int* index);

IPPFUN(Ipp64u, ippcpGetEnabledCpuFeatures, (void)) { return cpFeaturesMask; }

/*===================================================================*/
IPPFUN(IppStatus, ippcpGetCpuFeatures, (Ipp64u * pFeaturesMask))
{
    IPP_BAD_PTR1_RET(pFeaturesMask)
    {
        if (0 != cpFeatures) {
            *pFeaturesMask = cpFeatures; // & cpFeaturesMask;
        } else {
            int ret = cpGetFeatures(pFeaturesMask);
            if (!ret)
                return ippStsNotSupportedCpu;
        }
        return ippStsNoErr;
    }
}

/*===================================================================*/

int cpGetFeature(Ipp64u Feature)
{
// We provide users the ability to build their own custom build of 1cpu Intel® Cryptography Primitives Library
// and turn CPU features on at compile-time if they are sure these features available on the target systems.
#if (!defined(_MERGED_BLD) && defined(IPPCP_CUSTOM_BUILD))
    int if_feature_enabled = ((IPP_CUSTOM_ENABLED_FEATURES & Feature) == Feature);
    return if_feature_enabled;
#else
    if (0 == cpFeaturesMask) {
        Ipp64u loc_features;
        // set up cpFeaturesMask and cpFeatures for the proper work of tick-tok in 1cpu libraries
        ippcpGetCpuFeatures(&loc_features);
    }

    if ((cpFeaturesMask & Feature) == Feature) {
        return 1;
    } else {
        return 0;
    }
#endif
}

/*===================================================================*/
#define BIT00 0x00000001
#define BIT01 0x00000002
#define BIT02 0x00000004
#define BIT03 0x00000008
#define BIT04 0x00000010
#define BIT05 0x00000020
#define BIT06 0x00000040
#define BIT07 0x00000080
#define BIT08 0x00000100
#define BIT09 0x00000200
#define BIT10 0x00000400
#define BIT11 0x00000800
#define BIT12 0x00001000
#define BIT13 0x00002000
#define BIT14 0x00004000
#define BIT15 0x00008000
#define BIT16 0x00010000
#define BIT17 0x00020000
#define BIT18 0x00040000
#define BIT19 0x00080000
#define BIT20 0x00100000
#define BIT21 0x00200000
#define BIT22 0x00400000
#define BIT23 0x00800000
#define BIT24 0x01000000
#define BIT25 0x02000000
#define BIT26 0x04000000
#define BIT27 0x08000000
#define BIT28 0x10000000
#define BIT29 0x20000000
#define BIT30 0x40000000
#define BIT31 0x80000000


static int cpGetFeatures(Ipp64u* pFeaturesMask)
{
    Ipp32u buf[4];
    Ipp32u eax_, ebx_, ecx_, edx_, tmp;
    Ipp64u mask;
    int flgFMA = 0, flgINT = 0, flgGPR = 0;     // for avx2
    Ipp32u idBaseMax, idExtdMax;

    cpGetReg((int*)buf, 0, 0);                  //get max value for basic info.
    idBaseMax = buf[0];
    cpGetReg((int*)buf, (Ipp32s)0x80000000, 0); //get max value for extended info.
    idExtdMax = buf[0];

    cpGetReg((int*)buf, 1, 0);
    eax_ = (Ipp32u)buf[0];
    ecx_ = (Ipp32u)buf[2];
    edx_ = (Ipp32u)buf[3];
    mask = 0;
    if (edx_ & BIT23)
        mask |= ippCPUID_MMX;  // edx[23] - MMX(TM) Technology
    if (edx_ & BIT25)
        mask |= ippCPUID_SSE;  // edx[25] - Intel® Streaming SIMD Extensions (Intel® SSE)
    if (edx_ & BIT26)
        mask |= ippCPUID_SSE2; // edx[26] - Intel® Streaming SIMD Extensions 2 (Intel® SSE2)
    if (ecx_ & BIT00)
        // ecx[0]  - Intel® Streaming SIMD Extensions 3 (Intel® SSE3) (formerly codenamed Prescott)
        mask |= ippCPUID_SSE3;
    if (ecx_ & BIT09)
        // ecx[9]  - Supplemental Streaming SIMD Extensions 3 (SSSE3) (formerly codenamed Merom)
        mask |= ippCPUID_SSSE3;
    if (ecx_ & BIT22)
        mask |= ippCPUID_MOVBE; // ecx[22] - Intel® instruction MOVBE (Intel Atom® processor)
    if (ecx_ & BIT19)
        // ecx[19] - Intel® Streaming SIMD Extensions 4.1 (Intel® SSE4.1) (formerly codenamed Penryn)
        mask |= ippCPUID_SSE41;
    if (ecx_ & BIT20)
        // ecx[20] - Intel® Streaming SIMD Extensions 4.2 (Intel® SSE4.2) (formerly codenamed Nenalem)
        mask |= ippCPUID_SSE42;
    if (ecx_ & BIT28)
        // ecx[28] - Intel® Advanced Vector Extensions (Intel® AVX) (formerly codenamed Sandy Bridge)
        mask |= ippCPUID_AVX;
    if ((ecx_ & 0x18000000) == 0x18000000) {
        tmp = (Ipp32u)cp_is_avx_extension();
        if (tmp & BIT00)
            mask |= ippAVX_ENABLEDBYOS; // Intel® AVX is supported by OS
    }
    if (ecx_ & BIT25)
        mask |= ippCPUID_AES;           // ecx[25] - Intel® AES New Instructions
    if (ecx_ & BIT01)
        mask |= ippCPUID_CLMUL;         // ecx[1]  - Intel® instruction PCLMULQDQ
    if (ecx_ & BIT30)
        mask |= ippCPUID_RDRAND;        // ecx[30] - Intel® instruction RDRRAND
    if (ecx_ & BIT29)
        mask |= ippCPUID_F16C;          // ecx[29] - Intel® instruction F16C
    // Intel® AVX2 instructions extension: only if 3 features are enabled at once:
    // FMA, Intel® AVX 256 int & GPR BMI (bit-manipulation);
    if (ecx_ & BIT12)
        flgFMA = 1;
    else
        flgFMA = 0;       // ecx[12] - FMA 128 & 256 bit
    if (idBaseMax >= 7) { // get CPUID.eax = 7
        cpGetReg((int*)buf, 0x7, 0);
        ebx_ = (Ipp32u)buf[1];
        ecx_ = (Ipp32u)buf[2];
        edx_ = (Ipp32u)buf[3];
        if (ebx_ & BIT05)
            flgINT = 1;
        else
            flgINT = 0; //ebx[5], Intel® Advanced Vector Extensions 2 (Intel® AVX2) (int 256bits)
        // ebx[3] - enabled ANDN, BEXTR, BLSI, BLSMK, BLSR, TZCNT
        // ebx[8] - enabled BZHI, MULX, PDEP, PEXT, RORX, SARX, SHLX, SHRX
        if ((ebx_ & BIT03) && (ebx_ & BIT08))
            flgGPR = 1;
        else
            flgGPR = 0; // VEX-encoded GPR instructions (GPR BMI)
        // Intel® architecture formerly codenamed Broadwell instructions extension
        if (ebx_ & BIT19)
            // eax[0x7] -->> ebx:: Bit 19: Intel® instructions ADOX/ADCX
            mask |= ippCPUID_ADCOX;
        if (ebx_ & BIT18)
            // eax[0x7] -->> ebx:: Bit 18: Intel® instruction RDSEED
            mask |= ippCPUID_RDSEED;
        if (ebx_ & BIT29)
            // eax[0x7] -->> ebx:: Bit 29: Intel® Secure Hash Algorithm Extensions
            mask |= ippCPUID_SHA;

        if (ecx_ & BIT09)
            mask |= ippCPUID_AVX2VAES;   // ecx[09] - Intel® Vector AES instruction set
        if (ecx_ & BIT10)
            mask |= ippCPUID_AVX2VCLMUL; // ecx[10] - Intel® instruction VPCLMULQDQ

        // Intel® Advanced Vector Extensions 512 (Intel® AVX-512) extension
        if (ebx_ & BIT16)
            mask |= ippCPUID_AVX512F;  // ebx[16] - Intel® AVX-512 Foundation
        if (ebx_ & BIT26)
            mask |= ippCPUID_AVX512PF; // ebx[26] - Intel® AVX-512 Pre Fetch Instructions (PFI)
        if (ebx_ & BIT27)
            // ebx[27] - Intel® AVX-512 Exponential and Reciprocal Instructions (ERI)
            mask |= ippCPUID_AVX512ER;
        if (ebx_ & BIT28)
            mask |= ippCPUID_AVX512CD; // ebx[28] - Intel® AVX-512 Conflict Detection
        if (ebx_ & BIT17)
            mask |= ippCPUID_AVX512DQ; // ebx[17] - Intel® AVX-512 Dword & Quadword
        if (ebx_ & BIT30)
            mask |= ippCPUID_AVX512BW; // ebx[30] - Intel® AVX-512 Byte & Word
        if (ebx_ & BIT31)
            mask |= ippCPUID_AVX512VL; // ebx[31] - Intel® AVX-512 Vector Length Extensions (VLE)
        if (ecx_ & BIT01)
            // ecx[01] - Intel® AVX-512 Vector Bit Manipulation Instructions
            mask |= ippCPUID_AVX512VBMI;
        if (ecx_ & BIT06)
            // ecx[06] - Intel® AVX-512 Vector Bit Manipulation Instructions 2
            mask |= ippCPUID_AVX512VBMI2;
        if (edx_ & BIT02)
            // edx[02] - Intel® AVX-512 Vector instructions for deep learning enhanced word variable precision
            mask |= ippCPUID_AVX512_4VNNIW;
        if (edx_ & BIT03)
            // edx[03] - Intel® AVX-512 Vector instructions for deep learning floating-point single precision
            mask |= ippCPUID_AVX512_4FMADDPS;
        // bitwise OR between ippCPUID_MPX & ippCPUID_AVX flags can be used to define that arch is GE than formerly codenamed Skylake
        if (ebx_ & BIT14)
            mask |= ippCPUID_MPX; // ebx[14] - Intel® Memory Protection Extensions (Intel® MPX)
        if (ebx_ & BIT21)
            mask |= ippCPUID_AVX512IFMA;   // ebx[21] - Intel® AVX-512 IFMA PMADD52

        if (ecx_ & BIT08)
            mask |= ippCPUID_AVX512GFNI;   // test bit ecx[08]
        if (ecx_ & BIT09)
            mask |= ippCPUID_AVX512VAES;   // test bit ecx[09]
        if (ecx_ & BIT10)
            mask |= ippCPUID_AVX512VCLMUL; // test bit ecx[10]

        cpGetReg((int*)buf, 0x7, 1);       // Intel® SM3, SM4, and SHA512 instructions set check
        eax_ = (Ipp32u)buf[0];
        if (eax_ & BIT00)
            mask |= ippCPUID_AVX2SHA512;   // test bit eax[00]
        if (eax_ & BIT01)
            mask |= ippCPUID_AVX2SM3;      // test bit eax[01]
        if (eax_ & BIT02)
            mask |= ippCPUID_AVX2SM4;      // test bit eax[02]


        if (mask & ippCPUID_AVX512F) {
            /* test if Intel® AVX-512 is supported by OS */
            if (cp_is_avx512_extension())
                mask |= ippAVX512_ENABLEDBYOS;
        }

        cpGetReg((int*)buf, 0x7, 1);
        edx_ = (Ipp32u)buf[3];
        if (edx_ & BIT19) {             // edx[19] - AVX10 Converged Vector ISA
            cpGetReg((int*)buf, 0x24, 0);
            ebx_ = (Ipp32u)buf[1];
            if ((ebx_ & 0x00ff) >= 2) { // ebx[0:7] - AVX10 version 2
                mask |= ippCPUID_AVX10_2;
            }
        }
    }
    mask = (flgFMA && flgINT && flgGPR) ? (mask | ippCPUID_AVX2)
                                        : mask; // to separate Intel® AVX2 flags here

    if (idExtdMax >= 0x80000001) {              // get CPUID.eax=0x80000001
        cpGetReg((int*)buf, (Ipp32s)0x80000001, 0);
        ecx_ = (Ipp32u)buf[2];
        // Intel® architecture formerly codenamed Broadwell instructions extension
        if (ecx_ & BIT08)
            mask |=
                ippCPUID_PREFETCHW; // eax[0x80000001] -->> ecx:: Bit 8: Intel® instruction PREFETCHW
    }
    // Intel® architecture formerly codenamed Knights Corner
    if ((((eax_ << 20) >> 24) ^ 0xb1) == 0) {
        mask = mask | ippCPUID_KNC;
    }
    cpFeatures     = mask;
    cpFeaturesMask = mask; /* all CPU features are enabled by default */
    *pFeaturesMask = cpFeatures;
    return 1; /* if somebody need to check for cpuid support - do it at the top of function and return 0 if it's not supported */
}

int ippcpJumpIndexForMergedLibs   = -1;
static int cpthreads_omp_of_n_ipp = 1;

IPPFUN(int, ippcpGetEnabledNumThreads, (void)) { return cpthreads_omp_of_n_ipp; }


#define AVX3X_FEATURES                                                              \
    (ippCPUID_AVX512F | ippCPUID_AVX512CD | ippCPUID_AVX512VL | ippCPUID_AVX512BW | \
     ippCPUID_AVX512DQ)
#define AVX3M_FEATURES \
    (ippCPUID_AVX512F | ippCPUID_AVX512CD | ippCPUID_AVX512PF | ippCPUID_AVX512ER)
// AVX3X_FEATURES means Intel® Xeon® processor
// AVX3M_FEATURES means Intel® Many Integrated Core Architecture
#define AVX3I_FEATURES                                                            \
    (AVX3X_FEATURES | ippCPUID_SHA | ippCPUID_AVX512VBMI | ippCPUID_AVX512VBMI2 | \
     ippCPUID_AVX512IFMA | ippCPUID_AVX512GFNI | ippCPUID_AVX512VAES | ippCPUID_AVX512VCLMUL)

#define APX_FEATURES (AVX3I_FEATURES | ippCPUID_AVX10_2)


IppStatus owncpFeaturesToIdx(Ipp64u* cpuFeatures, int* index)
{
    IppStatus ownStatus = ippStsNoErr;
    Ipp64u mask         = 0;

    *index = 0;

    if ((APX_FEATURES == (*cpuFeatures & APX_FEATURES)) &&
        (ippAVX512_ENABLEDBYOS & cpFeatures)) { /* Intel® Advanced Vector Extensions 10.2 x64=D1 */
        mask   = APX_MSK;
        *index = LIB_APX;
    } else if ((AVX3I_FEATURES == (*cpuFeatures & AVX3I_FEATURES)) &&
               (ippAVX512_ENABLEDBYOS &
                cpFeatures)) { /* Intel® architecture formerly codenamed Icelake x64=K1 */
        mask   = AVX3I_MSK;
        *index = LIB_AVX3I;
    } else if ((AVX3X_FEATURES == (*cpuFeatures & AVX3X_FEATURES)) &&
               (ippAVX512_ENABLEDBYOS &
                cpFeatures)) { /* Intel® architecture formerly codenamed Skylake x64=K0 */
        mask   = AVX3X_MSK;
        *index = LIB_AVX3X;
    } else if ((ippCPUID_AVX2 == (*cpuFeatures & ippCPUID_AVX2)) &&
               (ippAVX_ENABLEDBYOS &
                cpFeatures)) { /* Intel® architecture formerly codenamed Haswell ia32=H9, x64=L9 */
        mask   = AVX2_MSK;
        *index = LIB_AVX2;
    } else if (ippCPUID_SSE42 == (*cpuFeatures & ippCPUID_SSE42) ||
               ippCPUID_AVX == (*cpuFeatures & ippCPUID_AVX)) {
        mask   = SSE42_MSK;
        *index = LIB_SSE42;
    } else {
        /* not supported, PX dispatched */
        mask   = MMX_MSK;
        *index = LIB_MMX;

        /* the lowest CPU supported by Intel Cryptography Primitives Library must at least support Intel® SSE42 for ia32 and x64 */
        ownStatus = ippStsNotSupportedCpu;
    }

    if ((mask != (*cpuFeatures & mask)) && (ownStatus == ippStsNoErr))
        ownStatus =
            ippStsFeaturesCombination; /* warning if combination of features is incomplete */
    *cpuFeatures |= mask;
    return ownStatus;
}


IPPFUN(IppStatus, ippcpSetNumThreads, (int numThr))
{
    IppStatus status = ippStsNoErr;

    IPP_UNREFERENCED_PARAMETER(numThr);
    status = ippStsNoOperation;

    return status;
}

IPPFUN(IppStatus, ippcpGetNumThreads, (int* pNumThr))
{
    IppStatus status = ippStsNoErr;
    IPP_BAD_PTR1_RET(pNumThr)

    *pNumThr = 1;
    status   = ippStsNoOperation;

    return status;
}

IPPFUN(IppStatus, ippcpInit, (void))
{
    Ipp64u cpuFeatures;

    ippcpGetCpuFeatures(&cpuFeatures);
    return ippcpSetCpuFeatures(cpuFeatures);
}


IPPFUN(IppStatus, ippcpSetCpuFeatures, (Ipp64u cpuFeatures))
{
    IppStatus ownStatus;
    int index = 0;

    ownStatus                   = owncpSetCpuFeaturesAndIdx(cpuFeatures, &index);
    ippcpJumpIndexForMergedLibs = index;
    cpFeaturesMask              = cpuFeatures;
    return ownStatus;
}

IppStatus owncpSetCpuFeaturesAndIdx(Ipp64u cpuFeatures, int* index)
{
    Ipp64u tmp;
    IppStatus tmpStatus;
    *index = 0;

    if (ippCPUID_NOCHECK & cpuFeatures) {
        // if NOCHECK is set - static variable cpFeatures is initialized unconditionally and real CPU features from CPUID are ignored;
        // the one who uses this method of initialization must understand what and why it does and the possible unpredictable consequences.
        // the only one known purpose for this approach - environments where CPUID instruction is disabled (for example Intel® Software Guard Extensions).
        cpuFeatures &= (IPP_MAX_64U ^ ippCPUID_NOCHECK);
        cpFeatures = cpuFeatures;
    } else
        /* read cpu features unconditionally */
        cpGetFeatures(&tmp);

    tmpStatus      = owncpFeaturesToIdx(&cpuFeatures, index);
    cpFeaturesMask = cpuFeatures;

    return tmpStatus;
}

static struct {
    int sts;
    const char* msg;
} ippcpMsg[] = {
    /* clang-format off */
/* ippStatus */
/* -9999 */ {ippStsCpuNotSupportedErr, "ippStsCpuNotSupportedErr: The target CPU is not supported"},
/* -9702 */ {MSG_NO_SHARED, "No shared libraries were found in the Waterfall procedure"},
/* -9701 */ {MSG_NO_DLL, "No DLLs were found in the Waterfall procedure"},
/* -9700 */ {MSG_LOAD_DLL_ERR, "Error at loading of %s library"},
/* -1019 */ {ippStsHashOperationErr, "ippStsHashOperationErr: An internal error occurred when hashing"},
/* -1018 */ {ippStsMLDSAMaxIterations, "ippStsMLDSAMaxIterations: The ML-DSA iterations reach maximum. Data weren't generated successfully"},
/* -1017 */ {ippStsInvalidPoint, "ippStsInvalidPoint ECC: Invalid point (out of EC)"},
/* -1016 */ {ippStsQuadraticNonResidueErr, "ippStsQuadraticNonResidueErr: SQRT operation on quadratic non-residue value"},
/* -1015 */ {ippStsPointAtInfinity, "ippStsPointAtInfinity: Point at infinity is detected"},
/* -1014 */ {ippStsOFBSizeErr, "ippStsOFBSizeErr: Incorrect value for cryptography OFB block size"},
/* -1013 */ {ippStsIncompleteContextErr, "ippStsIncompleteContextErr: Set up of context is not complete"},
/* -1012 */ {ippStsCTRSizeErr, "ippStsCTRSizeErr: Incorrect value for cryptography CTR block size"},
/* -1011 */ {ippStsEphemeralKeyErr, "ippStsEphemeralKeyErr: ECC: Invalid ephemeral key"},
/* -1010 */ {ippStsMessageErr, "ippStsMessageErr: ECC: Invalid message digest"},
/* -1009 */ {ippStsShareKeyErr, "ippStsShareKeyErr: ECC: Invalid share key"},
/* -1008 */ {ippStsInvalidPrivateKey, "ippStsInvalidPrivateKey ECC: Invalid private key"},
/* -1007 */ {ippStsOutOfECErr, "ippStsOutOfECErr: ECC: Point out of EC"},
/* -1006 */ {ippStsECCInvalidFlagErr, "ippStsECCInvalidFlagErr: ECC: Invalid Flag"},
/* -1005 */ {ippStsUnderRunErr, "ippStsUnderRunErr: Error in data under run"},
/* -1004 */ {ippStsPaddingErr, "ippStsPaddingErr: Detected padding error indicates the possible data corruption"},
/* -1003 */ {ippStsCFBSizeErr, "ippStsCFBSizeErr: Incorrect value for cryptography CFB block size"},
/* -1002 */ {ippStsPaddingSchemeErr, "ippStsPaddingSchemeErr: Invalid padding scheme"},
/* -1001 */ {ippStsBadModulusErr, "ippStsBadModulusErr: Bad modulus caused a failure in module inversion"},
/*  -216 */ {ippStsUnknownStatusCodeErr, "ippStsUnknownStatusCodeErr: Unknown status code"},
/*  -221 */ {ippStsLoadDynErr, "ippStsLoadDynErr: Error when loading the dynamic library"},
/*   -15 */ {ippStsLengthErr, "ippStsLengthErr: Incorrect value for string length"},
/*   -14 */ {ippStsNotSupportedModeErr, "ippStsNotSupportedModeErr: The requested mode is currently not supported"},
/*   -13 */ {ippStsContextMatchErr, "ippStsContextMatchErr: Context parameter does not match the operation"},
/*   -12 */ {ippStsScaleRangeErr, "ippStsScaleRangeErr: Scale bounds are out of range"},
/*   -11 */ {ippStsOutOfRangeErr, "ippStsOutOfRangeErr: Argument is out of range, or point is outside the image"},
/*   -10 */ {ippStsDivByZeroErr, "ippStsDivByZeroErr: An attempt to divide by zero"},
/*    -9 */ {ippStsMemAllocErr, "ippStsMemAllocErr: Memory allocated for the operation is not enough"},
/*    -8 */ {ippStsNullPtrErr, "ippStsNullPtrErr: Null pointer error"},
/*    -7 */ {ippStsRangeErr, "ippStsRangeErr: Incorrect values for bounds: the lower bound is greater than the upper bound"},
/*    -6 */ {ippStsSizeErr, "ippStsSizeErr: Incorrect value for data size"},
/*    -5 */ {ippStsBadArgErr, "ippStsBadArgErr: Incorrect arg/param of the function"},
/*    -4 */ {ippStsNoMemErr, "ippStsNoMemErr: Not enough memory for the operation"},
/*    -2 */ {ippStsErr, "ippStsErr: Unknown/unspecified error, -2"},
/*     0 */ {ippStsNoErr, "ippStsNoErr: No errors"},
/*     1 */ {ippStsNoOperation, "ippStsNoOperation: No operation has been executed"},
/*     2 */ {ippStsDivByZero, "ippStsDivByZero: Zero value(s) for the divisor in the Div function"},
/*    25 */ {ippStsInsufficientEntropy, "ippStsInsufficientEntropy: Generation of the prime/key failed due to insufficient entropy in the random seed and stimulus bit string"},
/*    36 */ {ippStsNotSupportedCpu, "ippStsNotSupportedCpu: The CPU is not supported"},
/*    48 */ {ippStsSizeWrn, "ippStsSizeWrn: The size does not allow to perform full operation"},
/*    51 */ {ippStsFeaturesCombination, "ippStsFeaturesCombination: Wrong combination of features"},
/*    53 */ {ippStsMbWarning, "ippStsMbWarning: Error(s) in statuses array"},
};
/* clang-format on */

/* /////////////////////////////////////////////////////////////////////////////
//  Name:       ippcpGetStatusString
//  Purpose:    transformation of a code of a status Intel Cryptography Primitives Library to string
//  Returns:
//  Parameters:
//    StsCode   Intel Cryptography Primitives Library status code
//
//  Notes:      not necessary to release the returned string
*/
IPPFUN(const char*, ippcpGetStatusString, (IppStatus StsCode))
{
    unsigned int i;
    for (i = 0; i < IPP_COUNT_OF(ippcpMsg); i++) {
        if (StsCode == ippcpMsg[i].sts) {
            return ippcpMsg[i].msg;
        }
    }
    return ippcpGetStatusString(ippStsUnknownStatusCodeErr);
}

extern IPP_OWN_DECL(Ipp64u, cp_get_pentium_counter, (void))

    /* /////////////////////////////////////////////////////////////////////////////
//  Name:       ippcpGetCpuClocks
//  Purpose:    time stamp counter (TSC) register reading
//  Returns:    TSC value
//
//  Note:      An hardware exception is possible if TSC reading is not supported by
//             the current chipset
*/
    IPPFUN(Ipp64u, ippcpGetCpuClocks, (void))
{
    return (Ipp64u)cp_get_pentium_counter();
}

#endif /* _IPP_DATA */
