• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 
3   This driver produces an EFI_RNG_PROTOCOL instance for the AMD Seattle CCP
4 
5   Copyright (C) 2016, Linaro Ltd. All rights reserved.<BR>
6 
7   This program and the accompanying materials are licensed and made available
8   under the terms and conditions of the BSD License which accompanies this
9   distribution. The full text of the license may be found at
10   http://opensource.org/licenses/bsd-license.php
11 
12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
13   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 #include <Library/BaseMemoryLib.h>
18 #include <Library/PcdLib.h>
19 #include <Library/IoLib.h>
20 
21 #include <Protocol/Rng.h>
22 
23 #define CCP_TRNG_OFFSET     0xc
24 #define CCP_TNRG_RETRIES    5
25 
26 STATIC EFI_PHYSICAL_ADDRESS mCcpRngOutputReg;
27 
28 STATIC EFI_HANDLE mHandle;
29 
30 /**
31   Returns information about the random number generation implementation.
32 
33   @param[in]     This                 A pointer to the EFI_RNG_PROTOCOL
34                                       instance.
35   @param[in,out] RNGAlgorithmListSize On input, the size in bytes of
36                                       RNGAlgorithmList.
37                                       On output with a return code of
38                                       EFI_SUCCESS, the size in bytes of the
39                                       data returned in RNGAlgorithmList. On
40                                       output with a return code of
41                                       EFI_BUFFER_TOO_SMALL, the size of
42                                       RNGAlgorithmList required to obtain the
43                                       list.
44   @param[out] RNGAlgorithmList        A caller-allocated memory buffer filled
45                                       by the driver with one EFI_RNG_ALGORITHM
46                                       element for each supported RNG algorithm.
47                                       The list must not change across multiple
48                                       calls to the same driver. The first
49                                       algorithm in the list is the default
50                                       algorithm for the driver.
51 
52   @retval EFI_SUCCESS                 The RNG algorithm list was returned
53                                       successfully.
54   @retval EFI_UNSUPPORTED             The services is not supported by this
55                                       driver.
56   @retval EFI_DEVICE_ERROR            The list of algorithms could not be
57                                       retrieved due to a hardware or firmware
58                                       error.
59   @retval EFI_INVALID_PARAMETER       One or more of the parameters are
60                                       incorrect.
61   @retval EFI_BUFFER_TOO_SMALL        The buffer RNGAlgorithmList is too small
62                                       to hold the result.
63 
64 **/
65 STATIC
66 EFI_STATUS
67 EFIAPI
StyxRngGetInfo(IN EFI_RNG_PROTOCOL * This,IN OUT UINTN * RNGAlgorithmListSize,OUT EFI_RNG_ALGORITHM * RNGAlgorithmList)68 StyxRngGetInfo (
69   IN      EFI_RNG_PROTOCOL        *This,
70   IN OUT  UINTN                   *RNGAlgorithmListSize,
71   OUT     EFI_RNG_ALGORITHM       *RNGAlgorithmList
72   )
73 {
74   if (This == NULL || RNGAlgorithmListSize == NULL) {
75     return EFI_INVALID_PARAMETER;
76   }
77 
78   if (*RNGAlgorithmListSize < sizeof (EFI_RNG_ALGORITHM)) {
79     *RNGAlgorithmListSize = sizeof (EFI_RNG_ALGORITHM);
80     return EFI_BUFFER_TOO_SMALL;
81   }
82 
83   if (RNGAlgorithmList == NULL) {
84     return EFI_INVALID_PARAMETER;
85   }
86 
87   *RNGAlgorithmListSize = sizeof (EFI_RNG_ALGORITHM);
88   CopyGuid (RNGAlgorithmList, &gEfiRngAlgorithmRaw);
89 
90   return EFI_SUCCESS;
91 }
92 
93 /**
94   Produces and returns an RNG value using either the default or specified RNG
95   algorithm.
96 
97   @param[in]  This                    A pointer to the EFI_RNG_PROTOCOL
98                                       instance.
99   @param[in]  RNGAlgorithm            A pointer to the EFI_RNG_ALGORITHM that
100                                       identifies the RNG algorithm to use. May
101                                       be NULL in which case the function will
102                                       use its default RNG algorithm.
103   @param[in]  RNGValueLength          The length in bytes of the memory buffer
104                                       pointed to by RNGValue. The driver shall
105                                       return exactly this numbers of bytes.
106   @param[out] RNGValue                A caller-allocated memory buffer filled
107                                       by the driver with the resulting RNG
108                                       value.
109 
110   @retval EFI_SUCCESS                 The RNG value was returned successfully.
111   @retval EFI_UNSUPPORTED             The algorithm specified by RNGAlgorithm
112                                       is not supported by this driver.
113   @retval EFI_DEVICE_ERROR            An RNG value could not be retrieved due
114                                       to a hardware or firmware error.
115   @retval EFI_NOT_READY               There is not enough random data available
116                                       to satisfy the length requested by
117                                       RNGValueLength.
118   @retval EFI_INVALID_PARAMETER       RNGValue is NULL or RNGValueLength is
119                                       zero.
120 
121 **/
122 STATIC
123 EFI_STATUS
124 EFIAPI
StyxRngGetRNG(IN EFI_RNG_PROTOCOL * This,IN EFI_RNG_ALGORITHM * RNGAlgorithm,OPTIONAL IN UINTN RNGValueLength,OUT UINT8 * RNGValue)125 StyxRngGetRNG (
126   IN EFI_RNG_PROTOCOL            *This,
127   IN EFI_RNG_ALGORITHM           *RNGAlgorithm, OPTIONAL
128   IN UINTN                       RNGValueLength,
129   OUT UINT8                      *RNGValue
130   )
131 {
132   UINT32 Val;
133   UINT32 Retries;
134   UINT32 Loop;
135 
136   if (This == NULL || RNGValueLength == 0 || RNGValue == NULL) {
137     return EFI_INVALID_PARAMETER;
138   }
139 
140   //
141   // We only support the raw algorithm, so reject requests for anything else
142   //
143   if (RNGAlgorithm != NULL &&
144       !CompareGuid (RNGAlgorithm, &gEfiRngAlgorithmRaw)) {
145     return EFI_UNSUPPORTED;
146   }
147 
148   do {
149     Retries = CCP_TNRG_RETRIES;
150     do {
151       Val = MmioRead32 (mCcpRngOutputReg);
152     } while (!Val && Retries-- > 0);
153 
154     if (!Val) {
155       return EFI_DEVICE_ERROR;
156     }
157 
158     for (Loop = 0; Loop < 4 && RNGValueLength > 0; Loop++, RNGValueLength--) {
159       *RNGValue++ = (UINT8)Val;
160       Val >>= 8;
161     }
162   } while (RNGValueLength > 0);
163 
164   return EFI_SUCCESS;
165 }
166 
167 STATIC EFI_RNG_PROTOCOL mStyxRngProtocol = {
168   StyxRngGetInfo,
169   StyxRngGetRNG
170 };
171 
172 //
173 // Entry point of this driver.
174 //
175 EFI_STATUS
176 EFIAPI
StyxRngEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)177 StyxRngEntryPoint (
178   IN EFI_HANDLE       ImageHandle,
179   IN EFI_SYSTEM_TABLE *SystemTable
180   )
181 {
182   mCcpRngOutputReg = PcdGet64 (PcdCCPBase) + CCP_TRNG_OFFSET;
183 
184   return SystemTable->BootServices->InstallMultipleProtocolInterfaces (
185                                       &mHandle,
186                                       &gEfiRngProtocolGuid, &mStyxRngProtocol,
187                                       NULL
188                                       );
189 }
190