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