/****************************************************************************** * * Copyright (C) 2013 - 2014 Xilinx, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * Use of the Software is limited solely to applications: * (a) running on a Xilinx device, or * (b) that interact with a Xilinx device through a bus or interconnect. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of the Xilinx shall not be used * in advertising or otherwise to promote the sale, use or other dealings in * this Software without prior written authorization from Xilinx. * ******************************************************************************/ /*****************************************************************************/ /** * @file xilskey_utils.c * * * @note None. * * * MODIFICATION HISTORY: * * Ver Who Date Changes * ----- ---- -------- -------------------------------------------------------- * 1.00a rpoolla 04/26/13 First release * 2.00 hk 22/01/14 Corrected PL voltage checks to VCCINT and VCCAUX. * CR#768077 * *****************************************************************************/ /***************************** Include Files ********************************/ #include "xil_io.h" #include "xil_types.h" #include "xilskey_utils.h" /************************** Constant Definitions ****************************/ /**************************** Type Definitions ******************************/ /***************** Macros (Inline Functions) Definitions ********************/ /************************** Variable Definitions ****************************/ static XAdcPs XAdcInst; /**< XADC driver instance */ u16 XAdcDeviceId; /**< XADC Device ID */ u32 TimerTicksfor100ns; /**< Global Variable to store ticks/100ns*/ /************************** Function Prototypes *****************************/ static u32 XilSKey_EfusePs_ConvertCharToNibble (char InChar, u8 *Num); /***************************************************************************/ /** * This function is used to initialize the XADC driver * * @return * - XST_SUCCESS in case of no errors. * - XSK_EFUSEPS_ERROR_XADC_CONFIG Error occurred with XADC config. * - XSK_EFUSEPS_ERROR_XADC_INITIALIZE Error occurred while XADC initialization * - XSK_EFUSEPS_ERROR_XADC_SELF_TEST Error occurred in XADC self test. * * TDD Cases: * ****************************************************************************/ u32 XilSKey_EfusePs_XAdcInit (void ) { u32 Status; XAdcPs_Config *ConfigPtr; XAdcPs *XAdcInstPtr = &XAdcInst; /** * specify the Device ID that is * generated in xparameters.h */ XAdcDeviceId=XADC_DEVICE_ID; /** * Initialize the XAdc driver. */ ConfigPtr = XAdcPs_LookupConfig(XAdcDeviceId); if (NULL == ConfigPtr) { return XSK_EFUSEPS_ERROR_XADC_CONFIG; } Status = XAdcPs_CfgInitialize(XAdcInstPtr, ConfigPtr, ConfigPtr->BaseAddress); if (Status != XST_SUCCESS) { return XSK_EFUSEPS_ERROR_XADC_INITIALIZE; } /** * Self Test the XADC/ADC device */ Status = XAdcPs_SelfTest(XAdcInstPtr); if (Status != XST_SUCCESS) { return XSK_EFUSEPS_ERROR_XADC_SELF_TEST; } /** * Disable the Channel Sequencer before configuring the Sequence * registers. */ XAdcPs_SetSequencerMode(XAdcInstPtr, XADCPS_SEQ_MODE_SAFE); return XST_SUCCESS; } /***************************************************************************/ /** * This function is used to copy the min, max and current value of the * temperature and voltage which are read from XADC. * * @param XAdcInstancePtr Pointer to the XSKEfusePs_XAdc. User has to * fill the VType to specify the type of voltage. Valid values * for VType are * - XSK_EFUSEPS_VPINT * - XSK_EFUSEPS_VPDRO * - XSK_EFUSEPS_VPAUX * - XSK_EFUSEPS_VINT * - XSK_EFUSEPS_VAUX * * @return none * * TDD Cases: * ****************************************************************************/ void XilSKey_EfusePs_XAdcReadTemperatureAndVoltage(XSKEfusePs_XAdc *XAdcInstancePtr) { XAdcPs *XAdcInstPtr = &XAdcInst; u8 V, VMin, VMax; if (NULL == XAdcInstPtr) { return; } /** * Read the on-chip Temperature Data (Current/Maximum/Minimum) * from the ADC data registers. */ XAdcInstancePtr->Temp = XAdcPs_GetAdcData(XAdcInstPtr, XADCPS_CH_TEMP); XAdcInstancePtr->TempMin = XAdcPs_GetMinMaxMeasurement(XAdcInstPtr, XADCPS_MIN_TEMP); XAdcInstancePtr->TempMax = XAdcPs_GetMinMaxMeasurement(XAdcInstPtr, XADCPS_MAX_TEMP); xeFUSE_printf(XSK_EFUSE_DEBUG_GENERAL, "Read Temperature Value: %0x -> %d in Centigrades \n", XAdcInstancePtr->Temp, (int )XAdcPs_RawToTemperature(XAdcInstancePtr->Temp)); /** * Read the VccPint Voltage Data (Current/Maximum/Minimum) from the * ADC data registers. */ switch (XAdcInstancePtr->VType) { case XSK_EFUSEPS_VINT: V = XADCPS_CH_VCCINT; VMax = XADCPS_MAX_VCCINT; VMin = XADCPS_MIN_VCCINT; break; case XSK_EFUSEPS_VAUX: V = XADCPS_CH_VCCAUX; VMax = XADCPS_MAX_VCCAUX; VMin = XADCPS_MIN_VCCAUX; break; case XSK_EFUSEPS_VPAUX: V = XADCPS_CH_VCCPAUX; VMax = XADCPS_MAX_VCCPAUX; VMin = XADCPS_MIN_VCCPAUX; break; case XSK_EFUSEPS_VPDRO: V = XADCPS_CH_VCCPDRO; VMax = XADCPS_MAX_VCCPDRO; VMin = XADCPS_MIN_VCCPDRO; break; case XSK_EFUSEPS_VPINT: default: V = XADCPS_CH_VCCPINT; VMax = XADCPS_MAX_VCCPINT; VMin = XADCPS_MIN_VCCPINT; break; } XAdcInstancePtr->V = XAdcPs_GetAdcData(XAdcInstPtr, V); XAdcInstancePtr->VMin = XAdcPs_GetMinMaxMeasurement(XAdcInstPtr, VMin); XAdcInstancePtr->VMax = XAdcPs_GetMinMaxMeasurement(XAdcInstPtr, VMax); xeFUSE_printf(XSK_EFUSE_DEBUG_GENERAL, "Read Voltage Value: %0x -> %d in Volts \n", XAdcInstancePtr->V, (int )XAdcPs_RawToVoltage(XAdcInstancePtr->V)); return; } /****************************************************************************/ /** * * Initializes the global timer & starts it. * Calculates the timer ticks for 1us. * * * * @param RefClk - reference clock * * @return * * None * * @note None. * *****************************************************************************/ void XilSKey_Efuse_StartTimer(u32 RefClk) { u32 arm_pll_fdiv,arm_clk_divisor; TimerTicksfor100ns = 0; /** * Extract PLL FDIV value from ARM PLL Control Register */ arm_pll_fdiv = (Xil_In32(XSK_ARM_PLL_CTRL_REG)>>12 & 0x7F); /** * Extract Clock divisor value from ARM Clock Control Register */ arm_clk_divisor = (Xil_In32(XSK_ARM_CLK_CTRL_REG)>>8 & 0x3F); /** * Calculate the Timer ticks per 100ns */ TimerTicksfor100ns = (((RefClk * arm_pll_fdiv)/arm_clk_divisor)/2)/10000000; /** * Disable the Timer counter */ Xil_Out32(XSK_GLOBAL_TIMER_CTRL_REG,0); /** * Write the lower 32 bit timer counter register. */ Xil_Out32(XSK_GLOBAL_TIMER_COUNT_REG_LOW, 0x0); /** * Write the upper 32 bit timer counter register. */ Xil_Out32(XSK_GLOBAL_TIMER_COUNT_REG_HIGH, 0x0); /** * Enable the Timer counter */ Xil_Out32(XSK_GLOBAL_TIMER_CTRL_REG,0x1); } /****************************************************************************/ /** * * Returns the timer ticks from start of timer to till now. * * @return * * t - Timer ticks lapsed till now. * * @note None. * *****************************************************************************/ u64 XilSKey_Efuse_GetTime(void) { volatile u32 t_hi=0, t_lo=0; volatile u64 t=0; do { t_hi = Xil_In32(XSK_GLOBAL_TIMER_COUNT_REG_HIGH); t_lo = Xil_In32(XSK_GLOBAL_TIMER_COUNT_REG_LOW); }while(t_hi != Xil_In32(XSK_GLOBAL_TIMER_COUNT_REG_HIGH)); t = (((u64) t_hi) << 32) | (u64) t_lo; return t; } /****************************************************************************/ /** * * Calculates the timer ticks to wait to set the time out * * @param t - timer ticks to wait to set the timeout * @param us - Timeout period in us * * * @return * t - timer ticks to wait to set the timeout * * @note None. * *****************************************************************************/ void XilSKey_Efuse_SetTimeOut(volatile u64* t, u64 us) { volatile u64 t_end; t_end = XilSKey_Efuse_GetTime(); /** * us: time to wait in microseconds. Convert to clock ticks and * add to current time. */ t_end += (us * TimerTicksfor100ns); *t = t_end; } /****************************************************************************/ /** * * Checks whether the timer has been expired or not * * @param t - timeout value in us * * @return * * t_end - Returns the global timer value in case of timer expired * * @note None. * *****************************************************************************/ u8 XilSKey_Efuse_IsTimerExpired(u64 t) { u64 t_end; t_end = XilSKey_Efuse_GetTime(); return t_end >= t; } /****************************************************************************/ /** * Converts the char into the equivalent nibble. * Ex: 'a' -> 0xa, 'A' -> 0xa, '9'->0x9 * * @param InChar is input character. It has to be between 0-9,a-f,A-F * @param Num is the output nibble. * @return * - XST_SUCCESS no errors occured. * - XST_FAILURE an error when input parameters are not valid ****************************************************************************/ static u32 XilSKey_EfusePs_ConvertCharToNibble (char InChar, u8 *Num) { /** * Convert the char to nibble */ if ((InChar >= '0') && (InChar <= '9')) *Num = InChar - '0'; else if ((InChar >= 'a') && (InChar <= 'f')) *Num = InChar - 'a' + 10; else if ((InChar >= 'A') && (InChar <= 'F')) *Num = InChar - 'A' + 10; else return XSK_EFUSEPS_ERROR_STRING_INVALID; return XST_SUCCESS; } /****************************************************************************/ /** * Converts the string into the equivalent Hex buffer. * Ex: "abc123" -> {0xab, 0xc1, 0x23} * * @param Str is a Input String. Will support the lower and upper case values. * Value should be between 0-9, a-f and A-F * * @param Buf is Output buffer. * @param Len of the input string. Should have even values * @return * - XST_SUCCESS no errors occured. * - XST_FAILURE an error when input parameters are not valid * - an error when input buffer has invalid values * * TDD Test Cases: ---Initialization--- Len is odd Len is zero Str is NULL Buf is NULL ---Functionality--- Str input with only numbers Str input with All values in A-F Str input with All values in a-f Str input with values in a-f, 0-9, A-F Str input with values in a-z, 0-9, A-Z Boundary Cases Memory Bounds of buffer checking ****************************************************************************/ u32 XilSKey_Efuse_ConvertStringToHexBE(const char * Str, u8 * Buf, u32 Len) { u32 ConvertedLen=0; u8 LowerNibble, UpperNibble; /** * Check the parameters */ if (Str == NULL) return XSK_EFUSEPS_ERROR_PARAMETER_NULL; if (Buf == NULL) return XSK_EFUSEPS_ERROR_PARAMETER_NULL; /** * Len has to be multiple of 2 */ if ((Len == 0) || (Len%2 == 1)) return XSK_EFUSEPS_ERROR_PARAMETER_NULL; ConvertedLen = 0; while (ConvertedLen < Len) { /** * Convert char to nibble */ if (XilSKey_EfusePs_ConvertCharToNibble (Str[ConvertedLen],&UpperNibble) ==XST_SUCCESS) { /** * Convert char to nibble */ if (XilSKey_EfusePs_ConvertCharToNibble (Str[ConvertedLen+1], &LowerNibble)==XST_SUCCESS) { /** * Merge upper and lower nibble to Hex */ Buf[ConvertedLen/2] = (UpperNibble << 4) | LowerNibble; } else { /** * Error converting Lower nibble */ return XSK_EFUSEPS_ERROR_STRING_INVALID; } } else { /** * Error converting Upper nibble */ return XSK_EFUSEPS_ERROR_STRING_INVALID; } /** * Converted upper and lower nibbles */ xeFUSE_printf(XSK_EFUSE_DEBUG_GENERAL,"Converted %c%c to %0x\n", Str[ConvertedLen],Str[ConvertedLen+1],Buf[ConvertedLen/2]); ConvertedLen += 2; } return XST_SUCCESS; } /****************************************************************************/ /** * Converts the string into the equivalent Hex buffer. * Ex: "abc123" -> {0x23, 0xc1, 0xab} * * @param Str is a Input String. Will support the lower and upper case values. * Value should be between 0-9, a-f and A-F * * @param Buf is Output buffer. * @param Len of the input string. Should have even values * @return * - XST_SUCCESS no errors occured. * - XST_FAILURE an error when input parameters are not valid * - an error when input buffer has invalid values * * TDD Test Cases: ---Initialization--- Len is odd Len is zero Str is NULL Buf is NULL ---Functionality--- Str input with only numbers Str input with All values in A-F Str input with All values in a-f Str input with values in a-f, 0-9, A-F Str input with values in a-z, 0-9, A-Z Boundary Cases Memory Bounds of buffer checking ****************************************************************************/ u32 XilSKey_Efuse_ConvertStringToHexLE(const char * Str, u8 * Buf, u32 Len) { u32 ConvertedLen=0; u8 LowerNibble, UpperNibble; u32 index; /** * Check the parameters */ if (Str == NULL) return XSK_EFUSEPS_ERROR_PARAMETER_NULL; if (Buf == NULL) return XSK_EFUSEPS_ERROR_PARAMETER_NULL; /** * Len has to be multiple of 2 */ if ((Len == 0) || (Len%2 == 1)) return XSK_EFUSEPS_ERROR_PARAMETER_NULL; index = (Len/8) - 1; ConvertedLen = 0; while (ConvertedLen < Len) { /** * Convert char to nibble */ if (XilSKey_EfusePs_ConvertCharToNibble (Str[ConvertedLen], &UpperNibble) == XST_SUCCESS) { /** * Convert char to nibble */ if (XilSKey_EfusePs_ConvertCharToNibble (Str[ConvertedLen+1], &LowerNibble)==XST_SUCCESS) { /** * Merge upper and lower nibble to Hex */ Buf[index--] = (UpperNibble << 4) | LowerNibble; } else { /** * Error converting Lower nibble */ return XSK_EFUSEPS_ERROR_STRING_INVALID; } } else { /** * Error converting Upper nibble */ return XSK_EFUSEPS_ERROR_STRING_INVALID; } /** * Converted upper and lower nibbles */ ConvertedLen += 2; } return XST_SUCCESS; } /***************************************************************************/ /** * This function is used to convert the Big Endian Byte data to * Little Endian Byte data * For ex: 1234567890abcdef -> 78563412efcdab90 * * @param Be Big endian data * @param Le Little endian data * @param Len Length of data to be converted and it should be multiple of 4 * @return * - XST_SUCCESS no errors occurred. * - XST_FAILURE an error occurred during reading the PS eFUSE. * * TDD Test Cases: * ****************************************************************************/ void XilSKey_EfusePs_ConvertBytesBeToLe(const u8 *Be, u8 *Le, u32 Len) { u32 Index; if ((Be == NULL) || (Le == NULL) || (Len == 0)) return; for (Index=0;Index {0, 0, 1, 1, 1, 0, 1, 0} * * @param Bits Input Buffer. * @param Bytes is Output buffer. * @param Len of the input buffer in bits * @return None Test Cases: Input with All Zeroes Input with All Ones Input Little Endian (General Cases ) Input Check Big Endian - False case Check for Len not a multiple of 8 Check for Len 0 Memory Bounds of buffer checking ****************************************************************************/ void XilSKey_Efuse_ConvertBitsToBytes(const u8 * Bits, u8 * Bytes, u32 Len) { u8 Data=0; u32 Index=0, BitIndex=0, ByteIndex=0; /** * Make sure the bytes array is 0'ed first. */ for(Index=0;Index MSB - Little Endian */ Data = (Bits[BitIndex] >> Index) & 0x1; Bytes[ByteIndex] = Data; ByteIndex++; Len--; /** * If len is not Byte aligned */ if(Len == 0) return; } BitIndex++; } return ; } /****************************************************************************/ /** * Convert the Bytes to Bits in little endian format * 0th byte is LSB, 7th byte is MSB * Ex: {0, 0, 1, 1, 1, 0, 1, 0} -> 0x5C * * @param Bytes Input Buffer. * @param Bits is Output buffer. * @param Len of the input buffer. * @return None Test Cases: Input with All Zeroes Input with All Ones Input Little Endian (General Cases ) Input Check Big Endian - False case Check for Len not a multiple of 8 Check for Len 0 Memory Bounds of buffer checking ****************************************************************************/ void XilSKey_EfusePs_ConvertBytesToBits(const u8 * Bytes, u8 * Bits , u32 Len) { u8 Tmp=0; u32 Index=0, BitIndex=0, ByteIndex=0; /** * Make sure the bits array is 0 first. */ for(Index=0;Index<((Len%8)?((Len/8)+1):(Len/8));Index++) { Bits[Index] = 0; } while(Len) { /** * Convert 1 Bit 8 Bytes to 8 Bit 1 Byte */ for(Index=0;Index<8;Index++) { /** * Store from LSB -> MSB - Little Endian */ Tmp = (Bytes[ByteIndex]) & 0x1; Bits[BitIndex] |= (Tmp << Index); ByteIndex++; Len--; /** * If Len is not Byte aligned */ if(Len == 0) return; } BitIndex++; } return; } /****************************************************************************/ /** * Validate the key for proper characters & proper length * * * @param Key - Hash Key * @param Len - Valid length of key * * @return * XST_SUCCESS - In case of Success * XST_FAILURE - In case of Failure ****************************************************************************/ u32 XilSKey_Efuse_ValidateKey(const char *Key, u32 Len) { int i; /** * Make sure passed key is not NULL */ if(Key == NULL) { return (XSK_EFUSEPL_ERROR_KEY_VALIDATION + XSK_EFUSEPL_ERROR_NULL_KEY); } if(Len == 0) { return (XSK_EFUSEPL_ERROR_KEY_VALIDATION + XSK_EFUSEPL_ERROR_ZERO_KEY_LENGTH); } /** * Make sure the key has valid length */ if (strlen(Key) != Len) { return (XSK_EFUSEPL_ERROR_KEY_VALIDATION + XSK_EFUSEPL_ERROR_NOT_VALID_KEY_LENGTH); } /** * Make sure the key has valid characters */ for(i=0;i