/** @file\r
Support routines for RDRAND instruction access.\r
\r
-Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
+#include <Library/RngLib.h>\r
\r
#include "RdRand.h"\r
#include "AesCore.h"\r
\r
-//\r
-// Bit mask used to determine if RdRand instruction is supported.\r
-//\r
-#define RDRAND_MASK 0x40000000\r
-\r
-/**\r
- Determines whether or not RDRAND instruction is supported by the host hardware.\r
-\r
- @retval EFI_SUCCESS RDRAND instruction supported.\r
- @retval EFI_UNSUPPORTED RDRAND instruction not supported.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-IsRdRandSupported (\r
- VOID\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT32 RegEax;\r
- UINT32 RegEbx;\r
- UINT32 RegEcx;\r
- UINT32 RegEdx;\r
- BOOLEAN IsIntelCpu;\r
-\r
- Status = EFI_UNSUPPORTED;\r
- IsIntelCpu = FALSE;\r
- \r
- //\r
- // Checks whether the current processor is an Intel product by CPUID.\r
- //\r
- AsmCpuid (0, &RegEax, &RegEbx, &RegEcx, &RegEdx);\r
- if ((CompareMem ((CHAR8 *)(&RegEbx), "Genu", 4) == 0) &&\r
- (CompareMem ((CHAR8 *)(&RegEdx), "ineI", 4) == 0) &&\r
- (CompareMem ((CHAR8 *)(&RegEcx), "ntel", 4) == 0)) {\r
- IsIntelCpu = TRUE;\r
- }\r
-\r
- if (IsIntelCpu) {\r
- //\r
- // Determine RDRAND support by examining bit 30 of the ECX register returned by CPUID.\r
- // A value of 1 indicates that processor supports RDRAND instruction.\r
- //\r
- AsmCpuid (1, 0, 0, &RegEcx, 0);\r
-\r
- if ((RegEcx & RDRAND_MASK) == RDRAND_MASK) {\r
- Status = EFI_SUCCESS;\r
- }\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Calls RDRAND to obtain a 16-bit random number.\r
-\r
- @param[out] Rand Buffer pointer to store the random result.\r
- @param[in] NeedRetry Determine whether or not to loop retry.\r
-\r
- @retval EFI_SUCCESS RDRAND call was successful.\r
- @retval EFI_NOT_READY Failed attempts to call RDRAND.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-RdRand16 (\r
- OUT UINT16 *Rand,\r
- IN BOOLEAN NeedRetry\r
- )\r
-{\r
- UINT32 Index;\r
- UINT32 RetryCount;\r
-\r
- if (NeedRetry) {\r
- RetryCount = RETRY_LIMIT;\r
- } else {\r
- RetryCount = 1;\r
- }\r
-\r
- //\r
- // Perform a single call to RDRAND, or enter a loop call until RDRAND succeeds.\r
- //\r
- for (Index = 0; Index < RetryCount; Index++) {\r
- if (RdRand16Step (Rand)) {\r
- return EFI_SUCCESS;\r
- }\r
- }\r
- \r
- return EFI_NOT_READY;\r
-}\r
-\r
-/**\r
- Calls RDRAND to obtain a 32-bit random number.\r
-\r
- @param[out] Rand Buffer pointer to store the random result.\r
- @param[in] NeedRetry Determine whether or not to loop retry.\r
-\r
- @retval EFI_SUCCESS RDRAND call was successful.\r
- @retval EFI_NOT_READY Failed attempts to call RDRAND.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-RdRand32 (\r
- OUT UINT32 *Rand,\r
- IN BOOLEAN NeedRetry\r
- )\r
-{\r
- UINT32 Index;\r
- UINT32 RetryCount;\r
-\r
- if (NeedRetry) {\r
- RetryCount = RETRY_LIMIT;\r
- } else {\r
- RetryCount = 1;\r
- }\r
-\r
- //\r
- // Perform a single call to RDRAND, or enter a loop call until RDRAND succeeds.\r
- //\r
- for (Index = 0; Index < RetryCount; Index++) {\r
- if (RdRand32Step (Rand)) {\r
- return EFI_SUCCESS;\r
- }\r
- }\r
- \r
- return EFI_NOT_READY;\r
-}\r
-\r
-/**\r
- Calls RDRAND to obtain a 64-bit random number.\r
-\r
- @param[out] Rand Buffer pointer to store the random result.\r
- @param[in] NeedRetry Determine whether or not to loop retry.\r
-\r
- @retval EFI_SUCCESS RDRAND call was successful.\r
- @retval EFI_NOT_READY Failed attempts to call RDRAND.\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-RdRand64 (\r
- OUT UINT64 *Rand,\r
- IN BOOLEAN NeedRetry\r
- )\r
-{\r
- UINT32 Index;\r
- UINT32 RetryCount;\r
-\r
- if (NeedRetry) {\r
- RetryCount = RETRY_LIMIT;\r
- } else {\r
- RetryCount = 1;\r
- }\r
-\r
- //\r
- // Perform a single call to RDRAND, or enter a loop call until RDRAND succeeds.\r
- //\r
- for (Index = 0; Index < RetryCount; Index++) {\r
- if (RdRand64Step (Rand)) {\r
- return EFI_SUCCESS;\r
- }\r
- }\r
- \r
- return EFI_NOT_READY;\r
-}\r
-\r
/**\r
Calls RDRAND to fill a buffer of arbitrary size with random bytes.\r
\r
OUT UINT8 *RandBuffer\r
)\r
{\r
- EFI_STATUS Status;\r
- UINT8 *Start;\r
- UINT8 *ResidualStart;\r
- UINTN *BlockStart;\r
- UINTN TempRand;\r
- UINTN Count;\r
- UINTN Residual;\r
- UINTN StartLen;\r
- UINTN BlockNum;\r
- UINTN Index;\r
-\r
- ResidualStart = NULL;\r
- TempRand = 0;\r
-\r
- //\r
- // Compute the address of the first word aligned (32/64-bit) block in the \r
- // destination buffer, depending on whether we are in 32- or 64-bit mode.\r
- //\r
- Start = RandBuffer;\r
- if (((UINT32)(UINTN)Start % (UINT32)sizeof(UINTN)) == 0) {\r
- BlockStart = (UINTN *)Start;\r
- Count = Length;\r
- StartLen = 0;\r
- } else {\r
- BlockStart = (UINTN *)(((UINTN)Start & ~(UINTN)(sizeof(UINTN) - 1)) + (UINTN)sizeof(UINTN));\r
- Count = Length - (sizeof (UINTN) - (UINT32)((UINTN)Start % sizeof (UINTN)));\r
- StartLen = (UINT32)((UINTN)BlockStart - (UINTN)Start);\r
- }\r
-\r
- //\r
- // Compute the number of word blocks and the remaining number of bytes.\r
- //\r
- Residual = Count % sizeof (UINTN);\r
- BlockNum = Count / sizeof (UINTN);\r
- if (Residual != 0) {\r
- ResidualStart = (UINT8 *) (BlockStart + BlockNum);\r
- }\r
-\r
- //\r
- // Obtain a temporary random number for use in the residuals. Failout if retry fails.\r
- //\r
- if (StartLen > 0) {\r
- Status = RdRandWord ((UINTN *) &TempRand, TRUE);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- }\r
+ BOOLEAN IsRandom;\r
+ UINT64 TempRand[2];\r
\r
- //\r
- // Populate the starting mis-aligned block.\r
- //\r
- for (Index = 0; Index < StartLen; Index++) {\r
- Start[Index] = (UINT8)(TempRand & 0xff);\r
- TempRand = TempRand >> 8;\r
- }\r
-\r
- //\r
- // Populate the central aligned block. Fail out if retry fails.\r
- //\r
- Status = RdRandGetWords (BlockNum, (UINTN *)(BlockStart));\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- //\r
- // Populate the final mis-aligned block.\r
- //\r
- if (Residual > 0) {\r
- Status = RdRandWord ((UINTN *)&TempRand, TRUE);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
+ while (Length > 0) {\r
+ IsRandom = GetRandomNumber128 (TempRand);\r
+ if (!IsRandom) {\r
+ return EFI_NOT_READY;\r
}\r
- for (Index = 0; Index < Residual; Index++) {\r
- ResidualStart[Index] = (UINT8)(TempRand & 0xff);\r
- TempRand = TempRand >> 8;\r
+ if (Length >= sizeof (TempRand)) {\r
+ WriteUnaligned64 ((UINT64*)RandBuffer, TempRand[0]);\r
+ RandBuffer += sizeof (UINT64);\r
+ WriteUnaligned64 ((UINT64*)RandBuffer, TempRand[1]);\r
+ RandBuffer += sizeof (UINT64);\r
+ Length -= sizeof (TempRand);\r
+ } else {\r
+ CopyMem (RandBuffer, TempRand, Length);\r
+ Length = 0;\r
}\r
}\r
\r
This function takes multiple random numbers through RDRAND without intervening\r
delays to ensure reseeding and performs AES-CBC-MAC over the data to compute the\r
seed value.\r
- \r
+\r
@param[out] SeedBuffer Pointer to a 128bit buffer to store the random seed.\r
\r
@retval EFI_SUCCESS Random seed generation succeeded.\r
UINT32 Index2;\r
\r
//\r
- // Chose an arbitary key and zero the feed_forward_value (FFV)\r
+ // Chose an arbitrary key and zero the feed_forward_value (FFV)\r
//\r
for (Index = 0; Index < 16; Index++) {\r
Key[Index] = (UINT8) Index;\r