Doman, Thanks for providing this.
In general, we like to put C functions that abstract CPU instructions in MdePkg/BaseLib. Do you think it makes sense to add 8/16/32/64 bit functions to BaseLib for the rdrand instruction. Then have the SecurityPkg library use the functions from BaseLib to execute rdrand instruction? Also, I see a fixed retry loop based on a #define. We prefer to use timeout values, so we do not have to adjust the loop count based on CPU speed. Can you update the retry loop to use TimerLib with a timeout period instead? Thanks, Mike -----Original Message----- From: Jonathan Doman [mailto:jonathan.do...@hp.com] Sent: Friday, June 19, 2015 10:48 AM To: edk2-devel@lists.sourceforge.net Subject: [edk2] [PATCH 1/2] SecurityPkg: Add RandLib from existing RngDxe code Separate out the low-level random data read code from RngDxe and move into new RandLib, including IA32 and X64 directories. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jonathan Doman <jonathan.do...@hp.com> --- SecurityPkg/Include/Library/RandLib.h | 50 +++++ SecurityPkg/Library/RandLib/IA32/AsmRdRand.asm | 67 ++++++ SecurityPkg/Library/RandLib/IA32/GccRdRand.c | 69 ++++++ SecurityPkg/Library/RandLib/IA32/RdRandWord.c | 104 +++++++++ SecurityPkg/Library/RandLib/RandLib.inf | 53 +++++ SecurityPkg/Library/RandLib/RdRand.c | 284 +++++++++++++++++++++++++ SecurityPkg/Library/RandLib/RdRand.h | 166 +++++++++++++++ SecurityPkg/Library/RandLib/X64/AsmRdRand.asm | 83 ++++++++ SecurityPkg/Library/RandLib/X64/GccRdRand.c | 95 +++++++++ SecurityPkg/Library/RandLib/X64/RdRandWord.c | 70 ++++++ SecurityPkg/SecurityPkg.dec | 3 + SecurityPkg/SecurityPkg.dsc | 1 + 12 files changed, 1045 insertions(+) create mode 100644 SecurityPkg/Include/Library/RandLib.h create mode 100644 SecurityPkg/Library/RandLib/IA32/AsmRdRand.asm create mode 100644 SecurityPkg/Library/RandLib/IA32/GccRdRand.c create mode 100644 SecurityPkg/Library/RandLib/IA32/RdRandWord.c create mode 100644 SecurityPkg/Library/RandLib/RandLib.inf create mode 100644 SecurityPkg/Library/RandLib/RdRand.c create mode 100644 SecurityPkg/Library/RandLib/RdRand.h create mode 100644 SecurityPkg/Library/RandLib/X64/AsmRdRand.asm create mode 100644 SecurityPkg/Library/RandLib/X64/GccRdRand.c create mode 100644 SecurityPkg/Library/RandLib/X64/RdRandWord.c diff --git a/SecurityPkg/Include/Library/RandLib.h b/SecurityPkg/Include/Library/RandLib.h new file mode 100644 index 0000000..f50c10e --- /dev/null +++ b/SecurityPkg/Include/Library/RandLib.h @@ -0,0 +1,50 @@ +/** @file RandLib.h + + Interfaces provided by RandLib to support RngDxe. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR> + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License that accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#ifndef __RAND_LIB_DOT_H__ +#define __RAND_LIB_DOT_H__ +#include <Uefi/UefiBaseType.h> + +/** + Determines whether or not RDRAND instruction is supported by the host hardware. + + @retval EFI_SUCCESS RDRAND instruction supported. + @retval EFI_UNSUPPORTED RDRAND instruction not supported. + +**/ +EFI_STATUS +EFIAPI +IsRdRandSupported ( + VOID + ); + +/** + Calls RDRAND to fill a buffer of arbitrary size with random bytes. + + @param[in] Length Size of the buffer, in bytes, to fill with. + @param[out] RandBuffer Pointer to the buffer to store the random result. + + @retval EFI_SUCCESS Random bytes generation succeeded. + @retval EFI_NOT_READY Failed to request random bytes. + +**/ +EFI_STATUS +EFIAPI +RdRandGetBytes ( + IN UINTN Length, + OUT UINT8 *RandBuffer + ); + +#endif /* __RAND_LIB_DOT_H__ */ diff --git a/SecurityPkg/Library/RandLib/IA32/AsmRdRand.asm b/SecurityPkg/Library/RandLib/IA32/AsmRdRand.asm new file mode 100644 index 0000000..37b3830 --- /dev/null +++ b/SecurityPkg/Library/RandLib/IA32/AsmRdRand.asm @@ -0,0 +1,67 @@ +;------------------------------------------------------------------------------ +; +; Copyright (c) 2013, Intel Corporation. All rights reserved.<BR> +; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; AsmRdRand.Asm +; +; Abstract: +; +; Implementation for 16-, and 32- invocations of RDRAND instruction under 32bit platform. +; +; Notes: +; +; Visual Studio coding practices do not use inline asm since multiple compilers and +; architectures are supported assembler not recognizing rdrand instruction so using DB's. +; +;------------------------------------------------------------------------------ + + .586P + .model flat, C + .code + +;------------------------------------------------------------------------------ +; Generate a 16 bit random number +; Return TRUE if Rand generated successfully, or FALSE if not +; +; BOOLEAN EFIAPI RdRand16Step (UINT16 *Rand); ECX +;------------------------------------------------------------------------------ +RdRand16Step PROC + ; rdrand ax ; generate a 16 bit RN into ax, CF=1 if RN generated ok, otherwise CF=0 + db 0fh, 0c7h, 0f0h ; rdrand r16: "0f c7 /6 ModRM:r/m(w)" + jb rn16_ok ; jmp if CF=1 + xor eax, eax ; reg=0 if CF=0 + ret ; return with failure status +rn16_ok: + mov [ecx], ax + mov eax, 1 + ret +RdRand16Step ENDP + +;------------------------------------------------------------------------------ +; Generate a 32 bit random number +; Return TRUE if Rand generated successfully, or FALSE if not +; +; BOOLEAN EFIAPI RdRand32Step (UINT32 *Rand); ECX +;------------------------------------------------------------------------------ +RdRand32Step PROC + ; rdrand eax ; generate a 32 bit RN into eax, CF=1 if RN generated ok, otherwise CF=0 + db 0fh, 0c7h, 0f0h ; rdrand r32: "0f c7 /6 ModRM:r/m(w)" + jb rn32_ok ; jmp if CF=1 + xor eax, eax ; reg=0 if CF=0 + ret ; return with failure status +rn32_ok: + mov [ecx], eax + mov eax, 1 + ret +RdRand32Step ENDP + + END diff --git a/SecurityPkg/Library/RandLib/IA32/GccRdRand.c b/SecurityPkg/Library/RandLib/IA32/GccRdRand.c new file mode 100644 index 0000000..f42302a --- /dev/null +++ b/SecurityPkg/Library/RandLib/IA32/GccRdRand.c @@ -0,0 +1,69 @@ +/** @file + RDRAND Support Routines for GCC environment. + +Copyright (c) 2013, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +/** + Generates a 16-bit random number through RDRAND instruction. + + @param[out] Rand Buffer pointer to store the random result. + + @retval TRUE RDRAND call was successful. + @retval FALSE Failed attempts to call RDRAND. + +**/ +BOOLEAN +EFIAPI +RdRand16Step ( + OUT UINT16 *Rand + ) +{ + UINT8 Carry; + + // + // Uses byte code for RDRAND instruction, + // in case that GCC version has no direct support on RDRAND assembly. + // + __asm__ __volatile__ ( + ".byte 0x66; .byte 0x0f; .byte 0xc7; .byte 0xf0; setc %1" + :"=a" (*Rand), + "=qm" (Carry) + ); + + return (BOOLEAN) Carry; +} + +/** + Generates a 32-bit random number through RDRAND instruction. + + @param[out] Rand Buffer pointer to store the random result. + + @retval TRUE RDRAND call was successful. + @retval FALSE Failed attempts to call RDRAND. + +**/ +BOOLEAN +EFIAPI +RdRand32Step ( + OUT UINT32 *Rand + ) +{ + UINT8 Carry; + + __asm__ __volatile__ ( + ".byte 0x0f; .byte 0xc7; .byte 0xf0; setc %1" + :"=a" (*Rand), + "=qm" (Carry) + ); + + return (BOOLEAN) Carry; +} \ No newline at end of file diff --git a/SecurityPkg/Library/RandLib/IA32/RdRandWord.c b/SecurityPkg/Library/RandLib/IA32/RdRandWord.c new file mode 100644 index 0000000..125c53b --- /dev/null +++ b/SecurityPkg/Library/RandLib/IA32/RdRandWord.c @@ -0,0 +1,104 @@ +/** @file + RDRAND Support Routines. + +Copyright (c) 2013, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "RdRand.h" + +/** + Generates a 64-bit random number through RDRAND instruction. + + @param[out] Rand Buffer pointer to store the random result. + + @retval TRUE RDRAND call was successful. + @retval FALSE Failed attempts to call RDRAND. + +**/ +BOOLEAN +EFIAPI +RdRand64Step ( + OUT UINT64 *Rand + ) +{ + UINT32 RandLow; + UINT32 RandHigh; + + // + // Generating a 64-bit rand on a 32-bit system by + // mapping two 32-bit RDRAND instructions. + // + if (!RdRand32Step (&RandLow)) { + return FALSE; + } + if (!RdRand32Step (&RandHigh)) { + return FALSE; + } + + *Rand = (UINT64) RandLow | LShiftU64 ((UINT64)RandHigh, 32); + + return TRUE; +} + +/** + Calls RDRAND to request a word-length random number. + + @param[out] Rand Buffer pointer to store the random number. + @param[in] NeedRetry Determine whether or not to loop retry. + + @retval EFI_SUCCESS Random word generation succeeded. + @retval EFI_NOT_READY Failed to request random word. + +**/ +EFI_STATUS +EFIAPI +RdRandWord ( + OUT UINTN *Rand, + IN BOOLEAN NeedRetry + ) +{ + return RdRand32 (Rand, NeedRetry); +} + +/** + Calls RDRAND to request multiple word-length random numbers. + + @param[in] Length Size of the buffer, in words, to fill with. + @param[out] RandBuffer Pointer to the buffer to store the random result. + + @retval EFI_SUCCESS Random words generation succeeded. + @retval EFI_NOT_READY Failed to request random words. + +**/ +EFI_STATUS +EFIAPI +RdRandGetWords ( + IN UINTN Length, + OUT UINTN *RandBuffer + ) +{ + EFI_STATUS Status; + UINT32 Index; + + for (Index = 0; Index < Length; Index++) { + // + // Obtain one word-length (32-bit) Random Number with possible retry-loop. + // + Status = RdRand32 (RandBuffer, TRUE); + if (EFI_ERROR (Status)) { + return Status; + } + + RandBuffer++; + } + + return EFI_SUCCESS; +} diff --git a/SecurityPkg/Library/RandLib/RandLib.inf b/SecurityPkg/Library/RandLib/RandLib.inf new file mode 100644 index 0000000..68f5cc7 --- /dev/null +++ b/SecurityPkg/Library/RandLib/RandLib.inf @@ -0,0 +1,53 @@ +## @file RandLib.inf +# +# Provide rand data using x86 instructions +# +# (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR> +# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License that accompanies this +# distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = IntelRandLib + FILE_GUID = D0317815-4036-2FF5-0F56-4990A7B37A6F + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RandLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.common] + RdRand.c + +[Sources.IA32] + IA32/RdRandWord.c + IA32/AsmRdRand.asm + IA32/GccRdRand.c | GCC + +[Sources.X64] + X64/RdRandWord.c + X64/AsmRdRand.asm + X64/GccRdRand.c | GCC + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[Depex] + TRUE + +[BuildOptions] + XCODE:*_*_*_CC_FLAGS = -mmmx -msse + diff --git a/SecurityPkg/Library/RandLib/RdRand.c b/SecurityPkg/Library/RandLib/RdRand.c new file mode 100644 index 0000000..3babbc3 --- /dev/null +++ b/SecurityPkg/Library/RandLib/RdRand.c @@ -0,0 +1,284 @@ +/** @file + Support routines for RDRAND instruction access. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR> + +Copyright (c) 2013, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "RdRand.h" +#include <Library/RandLib.h> + + +// +// Bit mask used to determine if RdRand instruction is supported. +// +#define RDRAND_MASK 0x40000000 + +/** + Determines whether or not RDRAND instruction is supported by the host hardware. + + @retval EFI_SUCCESS RDRAND instruction supported. + @retval EFI_UNSUPPORTED RDRAND instruction not supported. + +**/ +EFI_STATUS +EFIAPI +IsRdRandSupported ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 RegEax; + UINT32 RegEbx; + UINT32 RegEcx; + UINT32 RegEdx; + BOOLEAN IsIntelCpu; + + Status = EFI_UNSUPPORTED; + IsIntelCpu = FALSE; + + // + // Checks whether the current processor is an Intel product by CPUID. + // + AsmCpuid (0, &RegEax, &RegEbx, &RegEcx, &RegEdx); + if ((CompareMem ((CHAR8 *)(&RegEbx), "Genu", 4) == 0) && + (CompareMem ((CHAR8 *)(&RegEdx), "ineI", 4) == 0) && + (CompareMem ((CHAR8 *)(&RegEcx), "ntel", 4) == 0)) { + IsIntelCpu = TRUE; + } + + if (IsIntelCpu) { + // + // Determine RDRAND support by examining bit 30 of the ECX register returned by CPUID. + // A value of 1 indicates that processor supports RDRAND instruction. + // + AsmCpuid (1, 0, 0, &RegEcx, 0); + + if ((RegEcx & RDRAND_MASK) == RDRAND_MASK) { + Status = EFI_SUCCESS; + } + } + + return Status; +} + +/** + Calls RDRAND to obtain a 16-bit random number. + + @param[out] Rand Buffer pointer to store the random result. + @param[in] NeedRetry Determine whether or not to loop retry. + + @retval EFI_SUCCESS RDRAND call was successful. + @retval EFI_NOT_READY Failed attempts to call RDRAND. + +**/ +EFI_STATUS +EFIAPI +RdRand16 ( + OUT UINT16 *Rand, + IN BOOLEAN NeedRetry + ) +{ + UINT32 Index; + UINT32 RetryCount; + + if (NeedRetry) { + RetryCount = RETRY_LIMIT; + } else { + RetryCount = 1; + } + + // + // Perform a single call to RDRAND, or enter a loop call until RDRAND succeeds. + // + for (Index = 0; Index < RetryCount; Index++) { + if (RdRand16Step (Rand)) { + return EFI_SUCCESS; + } + } + + return EFI_NOT_READY; +} + +/** + Calls RDRAND to obtain a 32-bit random number. + + @param[out] Rand Buffer pointer to store the random result. + @param[in] NeedRetry Determine whether or not to loop retry. + + @retval EFI_SUCCESS RDRAND call was successful. + @retval EFI_NOT_READY Failed attempts to call RDRAND. + +**/ +EFI_STATUS +EFIAPI +RdRand32 ( + OUT UINT32 *Rand, + IN BOOLEAN NeedRetry + ) +{ + UINT32 Index; + UINT32 RetryCount; + + if (NeedRetry) { + RetryCount = RETRY_LIMIT; + } else { + RetryCount = 1; + } + + // + // Perform a single call to RDRAND, or enter a loop call until RDRAND succeeds. + // + for (Index = 0; Index < RetryCount; Index++) { + if (RdRand32Step (Rand)) { + return EFI_SUCCESS; + } + } + + return EFI_NOT_READY; +} + +/** + Calls RDRAND to obtain a 64-bit random number. + + @param[out] Rand Buffer pointer to store the random result. + @param[in] NeedRetry Determine whether or not to loop retry. + + @retval EFI_SUCCESS RDRAND call was successful. + @retval EFI_NOT_READY Failed attempts to call RDRAND. + +**/ +EFI_STATUS +EFIAPI +RdRand64 ( + OUT UINT64 *Rand, + IN BOOLEAN NeedRetry + ) +{ + UINT32 Index; + UINT32 RetryCount; + + if (NeedRetry) { + RetryCount = RETRY_LIMIT; + } else { + RetryCount = 1; + } + + // + // Perform a single call to RDRAND, or enter a loop call until RDRAND succeeds. + // + for (Index = 0; Index < RetryCount; Index++) { + if (RdRand64Step (Rand)) { + return EFI_SUCCESS; + } + } + + return EFI_NOT_READY; +} + +/** + Calls RDRAND to fill a buffer of arbitrary size with random bytes. + + @param[in] Length Size of the buffer, in bytes, to fill with. + @param[out] RandBuffer Pointer to the buffer to store the random result. + + @retval EFI_SUCCESS Random bytes generation succeeded. + @retval EFI_NOT_READY Failed to request random bytes. + +**/ +EFI_STATUS +EFIAPI +RdRandGetBytes ( + IN UINTN Length, + OUT UINT8 *RandBuffer + ) +{ + EFI_STATUS Status; + UINT8 *Start; + UINT8 *ResidualStart; + UINTN *BlockStart; + UINTN TempRand; + UINTN Count; + UINTN Residual; + UINTN StartLen; + UINTN BlockNum; + UINTN Index; + + ResidualStart = NULL; + TempRand = 0; + + // + // Compute the address of the first word aligned (32/64-bit) block in the + // destination buffer, depending on whether we are in 32- or 64-bit mode. + // + Start = RandBuffer; + if (((UINT32)(UINTN)Start % (UINT32)sizeof(UINTN)) == 0) { + BlockStart = (UINTN *)Start; + Count = Length; + StartLen = 0; + } else { + BlockStart = (UINTN *)(((UINTN)Start & ~(UINTN)(sizeof(UINTN) - 1)) + (UINTN)sizeof(UINTN)); + Count = Length - (sizeof (UINTN) - (UINT32)((UINTN)Start % sizeof (UINTN))); + StartLen = (UINT32)((UINTN)BlockStart - (UINTN)Start); + } + + // + // Compute the number of word blocks and the remaining number of bytes. + // + Residual = Count % sizeof (UINTN); + BlockNum = Count / sizeof (UINTN); + if (Residual != 0) { + ResidualStart = (UINT8 *) (BlockStart + BlockNum); + } + + // + // Obtain a temporary random number for use in the residuals. Failout if retry fails. + // + if (StartLen > 0) { + Status = RdRandWord ((UINTN *) &TempRand, TRUE); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Populate the starting mis-aligned block. + // + for (Index = 0; Index < StartLen; Index++) { + Start[Index] = (UINT8)(TempRand & 0xff); + TempRand = TempRand >> 8; + } + + // + // Populate the central aligned block. Fail out if retry fails. + // + Status = RdRandGetWords (BlockNum, (UINTN *)(BlockStart)); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Populate the final mis-aligned block. + // + if (Residual > 0) { + Status = RdRandWord ((UINTN *)&TempRand, TRUE); + if (EFI_ERROR (Status)) { + return Status; + } + for (Index = 0; Index < Residual; Index++) { + ResidualStart[Index] = (UINT8)(TempRand & 0xff); + TempRand = TempRand >> 8; + } + } + + return EFI_SUCCESS; +} + diff --git a/SecurityPkg/Library/RandLib/RdRand.h b/SecurityPkg/Library/RandLib/RdRand.h new file mode 100644 index 0000000..32dfc73 --- /dev/null +++ b/SecurityPkg/Library/RandLib/RdRand.h @@ -0,0 +1,166 @@ +/** @file + Header for the RDRAND APIs used by RNG DXE driver. + + Support API definitions for RDRAND instruction access, which will leverage + Intel Secure Key technology to provide high-quality random numbers for use + in applications, or entropy for seeding other random number generators. + Refer to http://software.intel.com/en-us/articles/intel-digital-random-number + -generator-drng-software-implementation-guide/ for more information about Intel + Secure Key technology. + + (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR> + +Copyright (c) 2013, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __RD_RAND_H__ +#define __RD_RAND_H__ + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Uefi/UefiBaseType.h> + +// +// The maximun number of retries to obtain one available random number. +// +#define RETRY_LIMIT 10 + +/** + Generates a 16-bit random number through RDRAND instruction. + + @param[out] Rand Buffer pointer to store the random result. + + @retval TRUE RDRAND call was successful. + @retval FALSE Failed attempts to call RDRAND. + +**/ +BOOLEAN +EFIAPI +RdRand16Step ( + OUT UINT16 *Rand + ); + +/** + Generates a 32-bit random number through RDRAND instruction. + + @param[out] Rand Buffer pointer to store the random result. + + @retval TRUE RDRAND call was successful. + @retval FALSE Failed attempts to call RDRAND. + +**/ +BOOLEAN +EFIAPI +RdRand32Step ( + OUT UINT32 *Rand + ); + +/** + Generates a 64-bit random number through RDRAND instruction. + + @param[out] Rand Buffer pointer to store the random result. + + @retval TRUE RDRAND call was successful. + @retval FALSE Failed attempts to call RDRAND. + +**/ +BOOLEAN +EFIAPI +RdRand64Step ( + OUT UINT64 *Rand + ); + +/** + Calls RDRAND to obtain a 16-bit random number. + + @param[out] Rand Buffer pointer to store the random result. + @param[in] NeedRetry Determine whether or not to loop retry. + + @retval EFI_SUCCESS RDRAND call was successful. + @retval EFI_NOT_READY Failed attempts to call RDRAND. + +**/ +EFI_STATUS +EFIAPI +RdRand16 ( + OUT UINT16 *Rand, + IN BOOLEAN NeedRetry + ); + +/** + Calls RDRAND to obtain a 32-bit random number. + + @param[out] Rand Buffer pointer to store the random result. + @param[in] NeedRetry Determine whether or not to loop retry. + + @retval EFI_SUCCESS RDRAND call was successful. + @retval EFI_NOT_READY Failed attempts to call RDRAND. + +**/ +EFI_STATUS +EFIAPI +RdRand32 ( + OUT UINT32 *Rand, + IN BOOLEAN NeedRetry + ); + +/** + Calls RDRAND to obtain a 64-bit random number. + + @param[out] Rand Buffer pointer to store the random result. + @param[in] NeedRetry Determine whether or not to loop retry. + + @retval EFI_SUCCESS RDRAND call was successful. + @retval EFI_NOT_READY Failed attempts to call RDRAND. + +**/ +EFI_STATUS +EFIAPI +RdRand64 ( + OUT UINT64 *Rand, + IN BOOLEAN NeedRetry + ); + +/** + Calls RDRAND to request a word-length random number. + + @param[out] Rand Buffer pointer to store the random number. + @param[in] NeedRetry Determine whether or not to loop retry. + + @retval EFI_SUCCESS Random word generation succeeded. + @retval EFI_NOT_READY Failed to request random word. + +**/ +EFI_STATUS +EFIAPI +RdRandWord ( + OUT UINTN *Rand, + IN BOOLEAN NeedRetry + ); + +/** + Calls RDRAND to request multiple word-length random numbers. + + @param[in] Length Size of the buffer, in words, to fill with. + @param[out] RandBuffer Pointer to the buffer to store the random result. + + @retval EFI_SUCCESS Random words generation succeeded. + @retval EFI_NOT_READY Failed to request random words. + +**/ +EFI_STATUS +EFIAPI +RdRandGetWords ( + IN UINTN Length, + OUT UINTN *RandBuffer + ); + +#endif // __RD_RAND_H__ diff --git a/SecurityPkg/Library/RandLib/X64/AsmRdRand.asm b/SecurityPkg/Library/RandLib/X64/AsmRdRand.asm new file mode 100644 index 0000000..8a4fe65 --- /dev/null +++ b/SecurityPkg/Library/RandLib/X64/AsmRdRand.asm @@ -0,0 +1,83 @@ +;------------------------------------------------------------------------------ +; +; Copyright (c) 2013, Intel Corporation. All rights reserved.<BR> +; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php. +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +; Module Name: +; +; AsmRdRand.Asm +; +; Abstract: +; +; Implementation for 16-, 32-, and 64-bit invocations of RDRAND instruction under 64bit platform. +; +; Notes: +; +; Visual Studio coding practices do not use inline asm since multiple compilers and +; architectures are supported assembler not recognizing rdrand instruction so using DB's. +; +;------------------------------------------------------------------------------ + + .code + +;------------------------------------------------------------------------------ +; Generate a 16 bit random number +; Return TRUE if Rand generated successfully, or FALSE if not +; +; BOOLEAN EFIAPI RdRand16Step (UINT16 *Rand); RCX +;------------------------------------------------------------------------------ +RdRand16Step PROC + ; rdrand ax ; generate a 16 bit RN into ax, CF=1 if RN generated ok, otherwise CF=0 + db 0fh, 0c7h, 0f0h ; rdrand r16: "0f c7 /6 ModRM:r/m(w)" + jb rn16_ok ; jmp if CF=1 + xor rax, rax ; reg=0 if CF=0 + ret ; return with failure status +rn16_ok: + mov [rcx], ax + mov rax, 1 + ret +RdRand16Step ENDP + +;------------------------------------------------------------------------------ +; Generate a 32 bit random number +; Return TRUE if Rand generated successfully, or FALSE if not +; +; BOOLEAN EFIAPI RdRand32Step (UINT32 *Rand); RCX +;------------------------------------------------------------------------------ +RdRand32Step PROC + ; rdrand eax ; generate a 32 bit RN into eax, CF=1 if RN generated ok, otherwise CF=0 + db 0fh, 0c7h, 0f0h ; rdrand r32: "0f c7 /6 ModRM:r/m(w)" + jb rn32_ok ; jmp if CF=1 + xor rax, rax ; reg=0 if CF=0 + ret ; return with failure status +rn32_ok: + mov [rcx], eax + mov rax, 1 + ret +RdRand32Step ENDP + +;------------------------------------------------------------------------------ +; Generate a 64 bit random number +; Return TRUE if RN generated successfully, or FALSE if not +; +; BOOLEAN EFIAPI RdRand64Step (UINT64 *Random); RCX +;------------------------------------------------------------------------------ +RdRand64Step PROC + ; rdrand rax ; generate a 64 bit RN into rax, CF=1 if RN generated ok, otherwise CF=0 + db 048h, 0fh, 0c7h, 0f0h ; rdrand r64: "REX.W + 0F C7 /6 ModRM:r/m(w)" + jb rn64_ok ; jmp if CF=1 + xor rax, rax ; reg=0 if CF=0 + ret ; return with failure status +rn64_ok: + mov [rcx], rax + mov rax, 1 + ret +RdRand64Step ENDP + + END diff --git a/SecurityPkg/Library/RandLib/X64/GccRdRand.c b/SecurityPkg/Library/RandLib/X64/GccRdRand.c new file mode 100644 index 0000000..d28336d --- /dev/null +++ b/SecurityPkg/Library/RandLib/X64/GccRdRand.c @@ -0,0 +1,95 @@ +/** @file + RDRAND Support Routines for GCC environment. + +Copyright (c) 2013, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +/** + Generates a 16-bit random number through RDRAND instruction. + + @param[out] Rand Buffer pointer to store the random result. + + @retval TRUE RDRAND call was successful. + @retval FALSE Failed attempts to call RDRAND. + +**/ +BOOLEAN +EFIAPI +RdRand16Step ( + OUT UINT16 *Rand + ) +{ + UINT8 Carry; + + // + // Uses byte code for RDRAND instruction, + // in case that GCC version has no direct support on RDRAND assembly. + // + __asm__ __volatile__ ( + ".byte 0x66; .byte 0x0f; .byte 0xc7; .byte 0xf0; setc %1" + :"=a" (*Rand), + "=qm" (Carry) + ); + + return (BOOLEAN) Carry; +} + +/** + Generates a 32-bit random number through RDRAND instruction. + + @param[out] Rand Buffer pointer to store the random result. + + @retval TRUE RDRAND call was successful. + @retval FALSE Failed attempts to call RDRAND. + +**/ +BOOLEAN +EFIAPI +RdRand32Step ( + OUT UINT32 *Rand + ) +{ + UINT8 Carry; + + __asm__ __volatile__ ( + ".byte 0x0f; .byte 0xc7; .byte 0xf0; setc %1" + :"=a" (*Rand), + "=qm" (Carry) + ); + + return (BOOLEAN) Carry; +} + +/** + Generates a 64-bit random number through RDRAND instruction. + + @param[out] Rand Buffer pointer to store the random result. + + @retval TRUE RDRAND call was successful. + @retval FALSE Failed attempts to call RDRAND. + +**/ +BOOLEAN +EFIAPI +RdRand64Step ( + OUT UINT64 *Rand + ) +{ + UINT8 Carry; + + __asm__ __volatile__ ( + ".byte 0x48; .byte 0x0f; .byte 0xc7; .byte 0xf0; setc %1" + :"=a" (*Rand), + "=qm" (Carry) + ); + + return (BOOLEAN) Carry; +} diff --git a/SecurityPkg/Library/RandLib/X64/RdRandWord.c b/SecurityPkg/Library/RandLib/X64/RdRandWord.c new file mode 100644 index 0000000..946e5ba --- /dev/null +++ b/SecurityPkg/Library/RandLib/X64/RdRandWord.c @@ -0,0 +1,70 @@ +/** @file + RDRAND Support Routines. + +Copyright (c) 2013, Intel Corporation. All rights reserved.<BR> +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "RdRand.h" + +/** + Calls RDRAND to request a word-length random number. + + @param[out] Rand Buffer pointer to store the random number. + @param[in] NeedRetry Determine whether or not to loop retry. + + @retval EFI_SUCCESS Random word generation succeeded. + @retval EFI_NOT_READY Failed to request random word. + +**/ +EFI_STATUS +EFIAPI +RdRandWord ( + OUT UINTN *Rand, + IN BOOLEAN NeedRetry + ) +{ + return RdRand64 (Rand, NeedRetry); +} + +/** + Calls RDRAND to request multiple word-length random numbers. + + @param[in] Length Size of the buffer, in words, to fill with. + @param[out] RandBuffer Pointer to the buffer to store the random result. + + @retval EFI_SUCCESS Random words generation succeeded. + @retval EFI_NOT_READY Failed to request random words. + +**/ +EFI_STATUS +EFIAPI +RdRandGetWords ( + IN UINTN Length, + OUT UINTN *RandBuffer + ) +{ + EFI_STATUS Status; + UINT32 Index; + + for (Index = 0; Index < Length; Index++) { + // + // Obtain one word-length (64-bit) Random Number with possible retry-loop. + // + Status = RdRand64 (RandBuffer, TRUE); + if (EFI_ERROR (Status)) { + return Status; + } + + RandBuffer++; + } + + return EFI_SUCCESS; +} \ No newline at end of file diff --git a/SecurityPkg/SecurityPkg.dec b/SecurityPkg/SecurityPkg.dec index 25ec7d0..8281deb 100644 --- a/SecurityPkg/SecurityPkg.dec +++ b/SecurityPkg/SecurityPkg.dec @@ -75,6 +75,9 @@ # TrEEPpVendorLib|Include/Library/TrEEPpVendorLib.h + ## @libraryclass Provides RDRAND. + RandLib|Include/Library/RandLib.h + [Guids] ## Security package token space guid. # Include/Guid/SecurityPkgTokenSpace.h diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc index 35a7a51..26758c3 100644 --- a/SecurityPkg/SecurityPkg.dsc +++ b/SecurityPkg/SecurityPkg.dsc @@ -59,6 +59,7 @@ TrEEPhysicalPresenceLib|SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/DxeTrEEPhysicalPresenceLib.inf TcgPpVendorLib|SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.inf TrEEPpVendorLib|SecurityPkg/Library/TrEEPpVendorLibNull/TrEEPpVendorLibNull.inf + RandLib|SecurityPkg/Library/RandLib/RandLib.inf [LibraryClasses.common.PEIM] PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf -- 2.4.3 ------------------------------------------------------------------------------ _______________________________________________ edk2-devel mailing list edk2-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/edk2-devel ------------------------------------------------------------------------------ _______________________________________________ edk2-devel mailing list edk2-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/edk2-devel