Jonathan Doman [mailto:jonathan.do...@hp.com] wrote:
]Sent: Friday, June 19, 2015 12:48 PM ]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 Is this using the correct calling convention? I think this is the 32-bit version, and EDK2 x86 32-bit code uses cdecl calling convention. If so, the passed value for arg1 is in [esp+4], not ecx. Same for all the other 32-bit asm functions here. ]+ 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) { What about non-Intel processors? I believe RDRAND has been adopted by at least one other x86 processor vendor in a compatible way, making it easy to support. In general EDK2 supports AMD and other x86 processors, so artificially excluding a compatible non-Intel RDRAND implementation seems wrong. ]+ // ]+ // 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