diff options
author | Dhaval <dhaval@rivosinc.com> | 2024-06-20 17:42:41 +0530 |
---|---|---|
committer | mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> | 2024-07-15 04:05:56 +0000 |
commit | b54bc983c6102a59c9e0472dd0406ac9ccbaa0bf (patch) | |
tree | a309d66b733e85f0da70e0872f6be20dc75b47e0 /MdePkg | |
parent | d4dbe5e101dcb86974f8dce3505b38343b83b432 (diff) | |
download | edk2-b54bc983c6102a59c9e0472dd0406ac9ccbaa0bf.tar.gz edk2-b54bc983c6102a59c9e0472dd0406ac9ccbaa0bf.tar.bz2 edk2-b54bc983c6102a59c9e0472dd0406ac9ccbaa0bf.zip |
MdePkg/Library: Add RISCV64 support to BaseRngLib
The ratified RISC-V crypto scalar extensions provide entropy bits via the
seed CSR, as exposed by the Zkr extension. The Zkr extension is ratified
and provides 16 bits of entropy seed when reading the SEED CSR.
Guarded by a RISCV64 Feature PCD, 64-bit random numbers can be
accumulated from the `seed` CSR. This driver is based on the driver in
the Linux kernel.
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Signed-off-by: Dhaval Sharma <dhaval@rivosinc.com>
Co-authored-by: Tim Wawrzynczak <tim@rivosinc.com>
Diffstat (limited to 'MdePkg')
-rw-r--r-- | MdePkg/Include/Register/RiscV64/RiscVEncoding.h | 10 | ||||
-rw-r--r-- | MdePkg/Library/BaseRngLib/BaseRngLib.inf | 8 | ||||
-rw-r--r-- | MdePkg/Library/BaseRngLib/Riscv/Rng.c | 277 | ||||
-rw-r--r-- | MdePkg/Library/BaseRngLib/Riscv/Seed.S | 19 | ||||
-rw-r--r-- | MdePkg/MdePkg.dec | 2 |
5 files changed, 316 insertions, 0 deletions
diff --git a/MdePkg/Include/Register/RiscV64/RiscVEncoding.h b/MdePkg/Include/Register/RiscV64/RiscVEncoding.h index 8ccdea2f4f..a656d443a5 100644 --- a/MdePkg/Include/Register/RiscV64/RiscVEncoding.h +++ b/MdePkg/Include/Register/RiscV64/RiscVEncoding.h @@ -120,4 +120,14 @@ #define CAUSE_VIRTUAL_INST_FAULT 0x16
#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17
+/* Sstc extension */
+#define CSR_SEED 0x15
+
+#define SEED_OPST_MASK 0xc0000000
+#define SEED_OPST_BIST 0x00000000
+#define SEED_OPST_WAIT 0x40000000
+#define SEED_OPST_ES16 0x80000000
+#define SEED_OPST_DEAD 0xc0000000
+#define SEED_ENTROPY_MASK 0xffff
+
#endif
diff --git a/MdePkg/Library/BaseRngLib/BaseRngLib.inf b/MdePkg/Library/BaseRngLib/BaseRngLib.inf index 49503b139b..a1614a900f 100644 --- a/MdePkg/Library/BaseRngLib/BaseRngLib.inf +++ b/MdePkg/Library/BaseRngLib/BaseRngLib.inf @@ -50,6 +50,10 @@ [Guids.Ia32, Guids.X64]
gEfiRngAlgorithmSp80090Ctr256Guid
+[Sources.RISCV64]
+ Riscv/Rng.c
+ Riscv/Seed.S | GCC
+
[Packages]
MdePkg/MdePkg.dec
@@ -59,3 +63,7 @@ [LibraryClasses]
BaseLib
DebugLib
+
+[Pcd.RISCV64]
+ # Does the CPU support the Zkr extension (for the `Seed` CSR)
+ gEfiMdePkgTokenSpaceGuid.PcdRiscVFeatureOverride ## CONSUMES
diff --git a/MdePkg/Library/BaseRngLib/Riscv/Rng.c b/MdePkg/Library/BaseRngLib/Riscv/Rng.c new file mode 100644 index 0000000000..305ab60b4d --- /dev/null +++ b/MdePkg/Library/BaseRngLib/Riscv/Rng.c @@ -0,0 +1,277 @@ +/** @file
+ Random number generator service that uses the SEED instruction
+ to provide pseudorandom numbers.
+
+ Copyright (c) 2024, Rivos, Inc.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+ **/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/RngLib.h>
+#include <Register/RiscV64/RiscVEncoding.h>
+
+#include "BaseRngLibInternals.h"
+#define RISCV_CPU_FEATURE_ZKR_BITMASK 0x8
+
+#define SEED_RETRY_LOOPS 100
+
+// 64-bit Mersenne Twister implementation
+// A widely used pseudo random number generator. It performs bit shifts etc to
+// achieve the random number. It's output is determined by SEED value generated
+// by RISC-V SEED CSR"
+
+#define STATE_SIZE 312
+#define MIDDLE 156
+#define INIT_SHIFT 62
+#define TWIST_MASK 0xb5026f5aa96619e9ULL
+#define INIT_FACT 6364136223846793005ULL
+#define SHIFT1 29
+#define MASK1 0x5555555555555555ULL
+#define SHIFT2 17
+#define MASK2 0x71d67fffeda60000ULL
+#define SHIFT3 37
+#define MASK3 0xfff7eee000000000ULL
+#define SHIFT4 43
+
+#define LOWER_MASK 0x7fffffff
+#define UPPER_MASK (~(UINT64)LOWER_MASK)
+
+static UINT64 mState[STATE_SIZE];
+static UINTN mIndex = STATE_SIZE + 1;
+
+/**
+ Initialize mState to defualt state.
+
+ @param[in] S Input seed value
+ **/
+STATIC
+VOID
+SeedRng (
+ IN UINT64 S
+ )
+{
+ UINTN I;
+
+ mIndex = STATE_SIZE;
+ mState[0] = S;
+
+ for (I = 1; I < STATE_SIZE; I++) {
+ mState[I] = (INIT_FACT * (mState[I - 1] ^ (mState[I - 1] >> INIT_SHIFT))) + I;
+ }
+}
+
+/**
+ Initializes mState with entropy values. The initialization is based on the
+ Seed value populated in mState[0] which then influences all the other values
+ in the mState array. Later values are retrieved from the same array instead
+ of calling trng instruction every time.
+
+ **/
+STATIC
+VOID
+TwistRng (
+ VOID
+ )
+{
+ UINTN I;
+ UINT64 X;
+
+ for (I = 0; I < STATE_SIZE; I++) {
+ X = (mState[I] & UPPER_MASK) | (mState[(I + 1) % STATE_SIZE] & LOWER_MASK);
+ X = (X >> 1) ^ (X & 1 ? TWIST_MASK : 0);
+ mState[I] = mState[(I + MIDDLE) % STATE_SIZE] ^ X;
+ }
+
+ mIndex = 0;
+}
+
+// Defined in Seed.S
+extern UINT64
+ReadSeed (
+ VOID
+ );
+
+/**
+ Gets seed value by executing trng instruction (CSR 0x15) amd returns
+ the see to the caller 64bit value.
+
+ @param[out] Out Buffer pointer to store the 64-bit random value.
+ @retval TRUE Random number generated successfully.
+ @retval FALSE Failed to generate the random number.
+ **/
+STATIC
+BOOLEAN
+Get64BitSeed (
+ OUT UINT64 *Out
+ )
+{
+ UINT64 Seed;
+ UINTN Retry;
+ UINTN ValidSeeds;
+ UINTN NeededSeeds;
+ UINT16 *Entropy;
+
+ Retry = SEED_RETRY_LOOPS;
+ Entropy = (UINT16 *)Out;
+ NeededSeeds = sizeof (UINT64) / sizeof (UINT16);
+ ValidSeeds = 0;
+
+ if (!ArchIsRngSupported ()) {
+ DEBUG ((DEBUG_ERROR, "Get64BitSeed: HW not supported!\n"));
+ return FALSE;
+ }
+
+ do {
+ Seed = ReadSeed ();
+
+ switch (Seed & SEED_OPST_MASK) {
+ case SEED_OPST_ES16:
+ Entropy[ValidSeeds++] = Seed & SEED_ENTROPY_MASK;
+ if (ValidSeeds == NeededSeeds) {
+ return TRUE;
+ }
+
+ break;
+
+ case SEED_OPST_DEAD:
+ DEBUG ((DEBUG_ERROR, "Get64BitSeed: Unrecoverable error!\n"));
+ return FALSE;
+
+ case SEED_OPST_BIST: // fallthrough
+ case SEED_OPST_WAIT: // fallthrough
+ default:
+ continue;
+ }
+ } while (--Retry);
+
+ return FALSE;
+}
+
+/**
+ Constructor library which initializes Seeds and mStatus array.
+
+ @retval EFI_SUCCESS Intialization was successful.
+ @retval EFI_UNSUPPORTED Feature not supported.
+
+ **/
+EFI_STATUS
+EFIAPI
+BaseRngLibConstructor (
+ VOID
+ )
+{
+ UINT64 Seed;
+
+ if (Get64BitSeed (&Seed)) {
+ SeedRng (Seed);
+ return EFI_SUCCESS;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+}
+
+/**
+ Generates a 16-bit random number.
+
+ @param[out] Rand Buffer pointer to store the 16-bit random value.
+
+ @retval TRUE Random number generated successfully.
+ @retval FALSE Failed to generate the random number.
+
+ **/
+BOOLEAN
+EFIAPI
+ArchGetRandomNumber16 (
+ OUT UINT16 *Rand
+ )
+{
+ UINT64 Rand64;
+
+ if (ArchGetRandomNumber64 (&Rand64)) {
+ *Rand = Rand64 & MAX_UINT16;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Generates a 32-bit random number.
+
+ @param[out] Rand Buffer pointer to store the 32-bit random value.
+
+ @retval TRUE Random number generated successfully.
+ @retval FALSE Failed to generate the random number.
+
+ **/
+BOOLEAN
+EFIAPI
+ArchGetRandomNumber32 (
+ OUT UINT32 *Rand
+ )
+{
+ UINT64 Rand64;
+
+ if (ArchGetRandomNumber64 (&Rand64)) {
+ *Rand = Rand64 & MAX_UINT32;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Generates a 64-bit random number.
+
+ @param[out] Rand Buffer pointer to store the 64-bit random value.
+
+ @retval TRUE Random number generated successfully.
+ @retval FALSE Failed to generate the random number.
+
+ **/
+BOOLEAN
+EFIAPI
+ArchGetRandomNumber64 (
+ OUT UINT64 *Rand
+ )
+{
+ UINT64 Y;
+
+ // Never initialized.
+ if (mIndex > STATE_SIZE) {
+ return FALSE;
+ }
+
+ // Mersenne Twister
+ if (mIndex == STATE_SIZE) {
+ TwistRng ();
+ }
+
+ Y = mState[mIndex];
+ Y ^= (Y >> SHIFT1) & MASK1;
+ Y ^= (Y << SHIFT2) & MASK2;
+ Y ^= (Y << SHIFT3) & MASK3;
+ Y ^= Y >> SHIFT4;
+
+ mIndex++;
+
+ *Rand = Y;
+ return TRUE;
+}
+
+/**
+ Checks whether SEED is supported.
+
+ @retval TRUE SEED is supported.
+ **/
+BOOLEAN
+EFIAPI
+ArchIsRngSupported (
+ VOID
+ )
+{
+ return ((PcdGet64 (PcdRiscVFeatureOverride) & RISCV_CPU_FEATURE_ZKR_BITMASK) != 0);
+}
diff --git a/MdePkg/Library/BaseRngLib/Riscv/Seed.S b/MdePkg/Library/BaseRngLib/Riscv/Seed.S new file mode 100644 index 0000000000..0028923395 --- /dev/null +++ b/MdePkg/Library/BaseRngLib/Riscv/Seed.S @@ -0,0 +1,19 @@ +//------------------------------------------------------------------------------
+//
+// RISC-V cache operation.
+//
+// Copyright (c) 2024, Rivos Inc. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//------------------------------------------------------------------------------
+
+#include <Register/RiscV64/RiscVImpl.h>
+
+.text
+ .p2align 4
+
+ASM_FUNC (ReadSeed)
+#The SEED CSR must only be accessed with read-write instructions
+csrrw a0, CSR_SEED, x0
+ret
diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec index 5dbe5a9f72..f8c30d3e76 100644 --- a/MdePkg/MdePkg.dec +++ b/MdePkg/MdePkg.dec @@ -2430,6 +2430,8 @@ # previous stage has feature enabled and user wants to disable it.
# BIT 2 = Page-Based Memory Types (Pbmt). This bit is relevant only if
# previous stage has feature enabled and user wants to disable it.
+ # BIT 3 = Zkr extension.This bit is relevant only if
+ # previous stage has feature enabled and user wants to disable it.
#
gEfiMdePkgTokenSpaceGuid.PcdRiscVFeatureOverride|0xFFFFFFFFFFFFFFFF|UINT64|0x69
|