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

Reply via email to